2 * WININET - Ftp implementation
4 * Copyright 1999 Corel Corporation
9 * Copyright 2000 Andreas Mohr
10 * Copyright 2002 Jaco Greeff
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include "wine/port.h"
34 #include <sys/types.h>
35 #ifdef HAVE_SYS_SOCKET_H
36 # include <sys/socket.h>
51 #include "wine/debug.h"
54 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
56 #define NOACCOUNT "noaccount"
57 #define DATA_PACKET_SIZE 0x2000
62 /* FTP commands with arguments. */
78 /* FTP commands without arguments. */
87 static const CHAR *szFtpCommands[] = {
110 static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
112 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
113 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
114 BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType);
115 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket);
116 BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile);
117 INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse,
118 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
119 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType);
120 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile);
121 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs);
122 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs);
123 BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs);
124 BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs);
125 BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType);
126 BOOL FTP_GetFileSize(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD *dwSize);
127 BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs);
128 BOOL FTP_DoPassive(LPWININETFTPSESSIONA lpwfs);
129 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs);
130 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp);
131 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp);
132 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket,
133 LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext);
134 DWORD FTP_SetResponseError(DWORD dwResponse);
136 inline static LPSTR FTP_strdup( LPCSTR str )
138 LPSTR ret = HeapAlloc( GetProcessHeap(), 0, strlen(str) + 1 );
139 if (ret) strcpy( ret, str );
143 /***********************************************************************
144 * FtpPutFileA (WININET.@)
146 * Uploads a file to the FTP server
153 BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
154 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
156 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
157 LPWININETAPPINFOA hIC = NULL;
159 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
161 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
165 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
166 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
168 WORKREQUEST workRequest;
170 workRequest.asyncall = FTPPUTFILEA;
171 workRequest.HFTPSESSION = (DWORD)hConnect;
172 workRequest.LPSZLOCALFILE = (DWORD)FTP_strdup(lpszLocalFile);
173 workRequest.LPSZNEWREMOTEFILE = (DWORD)FTP_strdup(lpszNewRemoteFile);
174 workRequest.DWFLAGS = dwFlags;
175 workRequest.DWCONTEXT = dwContext;
177 return INTERNET_AsyncCall(&workRequest);
181 return FTP_FtpPutFileA(hConnect, lpszLocalFile,
182 lpszNewRemoteFile, dwFlags, dwContext);
186 /***********************************************************************
187 * FTP_FtpPutFileA (Internal)
189 * Uploads a file to the FTP server
196 BOOL WINAPI FTP_FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
197 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
200 BOOL bSuccess = FALSE;
201 LPWININETAPPINFOA hIC = NULL;
202 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
205 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", lpszLocalFile, lpszNewRemoteFile);
206 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
208 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
212 /* Clear any error information */
213 INTERNET_SetLastError(0);
215 /* Open file to be uploaded */
216 if (INVALID_HANDLE_VALUE ==
217 (hFile = CreateFileA(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
219 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND);
223 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
224 if (hIC->lpfnStatusCB)
225 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
227 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
231 /* Get data socket to server */
232 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
234 FTP_SendData(lpwfs, nDataSocket, hFile);
236 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
237 MAX_REPLY_LEN, 0, 0, 0);
243 FTP_SetResponseError(nResCode);
249 if (lpwfs->lstnSocket != -1)
250 close(lpwfs->lstnSocket);
252 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
254 INTERNET_ASYNC_RESULT iar;
256 iar.dwResult = (DWORD)bSuccess;
257 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
258 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
259 &iar, sizeof(INTERNET_ASYNC_RESULT));
269 /***********************************************************************
270 * FtpSetCurrentDirectoryA (WININET.@)
272 * Change the working directory on the FTP server
279 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
281 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
282 LPWININETAPPINFOA hIC = NULL;
284 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
286 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
290 TRACE("lpszDirectory(%s)\n", lpszDirectory);
292 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
293 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
295 WORKREQUEST workRequest;
297 workRequest.asyncall = FTPSETCURRENTDIRECTORYA;
298 workRequest.HFTPSESSION = (DWORD)hConnect;
299 workRequest.LPSZDIRECTORY = (DWORD)FTP_strdup(lpszDirectory);
301 return INTERNET_AsyncCall(&workRequest);
305 return FTP_FtpSetCurrentDirectoryA(hConnect, lpszDirectory);
310 /***********************************************************************
311 * FtpSetCurrentDirectoryW (WININET.@)
313 * Change the working directory on the FTP server
320 BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
326 len = lstrlenW(lpszDirectory)+1;
327 if (!(szDir = (CHAR *)malloc(len*sizeof(CHAR))))
329 WideCharToMultiByte(CP_ACP, -1, lpszDirectory, -1, szDir, len, NULL, NULL);
330 rc = FtpSetCurrentDirectoryA(hConnect, szDir);
337 /***********************************************************************
338 * FTP_FtpSetCurrentDirectoryA (Internal)
340 * Change the working directory on the FTP server
347 BOOL WINAPI FTP_FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
350 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
351 LPWININETAPPINFOA hIC = NULL;
352 DWORD bSuccess = FALSE;
354 TRACE("lpszDirectory(%s)\n", lpszDirectory);
356 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
358 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
362 /* Clear any error information */
363 INTERNET_SetLastError(0);
365 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
366 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
367 hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
370 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
371 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
378 FTP_SetResponseError(nResCode);
382 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
384 INTERNET_ASYNC_RESULT iar;
386 iar.dwResult = (DWORD)bSuccess;
387 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
388 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
389 &iar, sizeof(INTERNET_ASYNC_RESULT));
395 /***********************************************************************
396 * FtpCreateDirectoryA (WININET.@)
398 * Create new directory on the FTP server
405 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
407 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
408 LPWININETAPPINFOA hIC = NULL;
410 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
412 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
416 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
417 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
419 WORKREQUEST workRequest;
421 workRequest.asyncall = FTPCREATEDIRECTORYA;
422 workRequest.HFTPSESSION = (DWORD)hConnect;
423 workRequest.LPSZDIRECTORY = (DWORD)FTP_strdup(lpszDirectory);
425 return INTERNET_AsyncCall(&workRequest);
429 return FTP_FtpCreateDirectoryA(hConnect, lpszDirectory);
434 /***********************************************************************
435 * FtpCreateDirectoryW (WININET.@)
437 * Create new directory on the FTP server
444 BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
450 len = lstrlenW(lpszDirectory)+1;
451 if (!(szDir = (CHAR *)malloc(len*sizeof(CHAR))))
453 WideCharToMultiByte(CP_ACP, -1, lpszDirectory, -1, szDir, len, NULL, NULL);
454 rc = FtpCreateDirectoryA(hConnect, szDir);
461 /***********************************************************************
462 * FTP_FtpCreateDirectoryA (Internal)
464 * Create new directory on the FTP server
471 BOOL WINAPI FTP_FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
474 BOOL bSuccess = FALSE;
475 LPWININETAPPINFOA hIC = NULL;
476 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
479 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
481 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
485 /* Clear any error information */
486 INTERNET_SetLastError(0);
488 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
491 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
492 MAX_REPLY_LEN, 0, 0, 0);
498 FTP_SetResponseError(nResCode);
502 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
503 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
505 INTERNET_ASYNC_RESULT iar;
507 iar.dwResult = (DWORD)bSuccess;
508 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
509 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
510 &iar, sizeof(INTERNET_ASYNC_RESULT));
517 /***********************************************************************
518 * FtpFindFirstFileA (WININET.@)
520 * Search the specified directory
523 * HINTERNET on success
527 HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
528 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
530 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
531 LPWININETAPPINFOA hIC = NULL;
533 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
535 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
539 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
540 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
542 WORKREQUEST workRequest;
544 workRequest.asyncall = FTPFINDFIRSTFILEA;
545 workRequest.HFTPSESSION = (DWORD)hConnect;
546 workRequest.LPSZSEARCHFILE = (DWORD)FTP_strdup(lpszSearchFile);
547 workRequest.LPFINDFILEDATA = (DWORD)lpFindFileData;
548 workRequest.DWFLAGS = dwFlags;
549 workRequest.DWCONTEXT= dwContext;
551 INTERNET_AsyncCall(&workRequest);
556 return FTP_FtpFindFirstFileA(hConnect, lpszSearchFile, lpFindFileData,
562 /***********************************************************************
563 * FtpFindFirstFileA (WININET.@)
565 * Search the specified directory
568 * HINTERNET on success
572 HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect,
573 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
580 /***********************************************************************
581 * FTP_FtpFindFirstFileA (Internal)
583 * Search the specified directory
586 * HINTERNET on success
590 HINTERNET WINAPI FTP_FtpFindFirstFileA(HINTERNET hConnect,
591 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
594 LPWININETAPPINFOA hIC = NULL;
595 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
596 LPWININETFINDNEXTA hFindNext = NULL;
600 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
602 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
606 /* Clear any error information */
607 INTERNET_SetLastError(0);
609 if (!FTP_InitListenSocket(lpwfs))
612 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
615 if (!FTP_SendPortOrPasv(lpwfs))
618 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
619 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, lpszSearchFile,
620 hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
623 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
624 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
627 if (nResCode == 125 || nResCode == 150)
631 /* Get data socket to server */
632 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
634 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpFindFileData, dwContext);
636 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
637 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
638 if (nResCode != 226 && nResCode != 250)
639 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
645 FTP_SetResponseError(nResCode);
649 if (lpwfs->lstnSocket != -1)
650 close(lpwfs->lstnSocket);
652 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
654 INTERNET_ASYNC_RESULT iar;
658 iar.dwResult = (DWORD)hFindNext;
659 iar.dwError = ERROR_SUCCESS;
660 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
661 &iar, sizeof(INTERNET_ASYNC_RESULT));
664 iar.dwResult = (DWORD)hFindNext;
665 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
666 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
667 &iar, sizeof(INTERNET_ASYNC_RESULT));
670 return (HINTERNET)hFindNext;
674 /***********************************************************************
675 * FtpGetCurrentDirectoryA (WININET.@)
677 * Retrieves the current directory
684 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
685 LPDWORD lpdwCurrentDirectory)
687 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
688 LPWININETAPPINFOA hIC = NULL;
690 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
692 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
694 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
698 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
699 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
701 WORKREQUEST workRequest;
703 workRequest.asyncall = FTPGETCURRENTDIRECTORYA;
704 workRequest.HFTPSESSION = (DWORD)hFtpSession;
705 workRequest.LPSZDIRECTORY = (DWORD)lpszCurrentDirectory;
706 workRequest.LPDWDIRECTORY = (DWORD)lpdwCurrentDirectory;
708 return INTERNET_AsyncCall(&workRequest);
712 return FTP_FtpGetCurrentDirectoryA(hFtpSession, lpszCurrentDirectory,
713 lpdwCurrentDirectory);
718 /***********************************************************************
719 * FtpGetCurrentDirectoryW (WININET.@)
721 * Retrieves the current directory
728 BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory,
729 LPDWORD lpdwCurrentDirectory)
736 /***********************************************************************
737 * FTP_FtpGetCurrentDirectoryA (Internal)
739 * Retrieves the current directory
746 BOOL WINAPI FTP_FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
747 LPDWORD lpdwCurrentDirectory)
750 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
751 LPWININETAPPINFOA hIC = NULL;
752 DWORD bSuccess = FALSE;
754 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
756 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
758 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
762 /* Clear any error information */
763 INTERNET_SetLastError(0);
765 ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
767 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
768 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
769 hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext))
772 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
773 MAX_REPLY_LEN, hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext);
776 if (nResCode == 257) /* Extract directory name */
778 INT firstpos, lastpos, len;
779 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
781 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
783 if ('"' == lpszResponseBuffer[lastpos])
792 len = lastpos - firstpos - 1;
793 strncpy(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1],
794 len < *lpdwCurrentDirectory ? len : *lpdwCurrentDirectory);
795 *lpdwCurrentDirectory = len;
799 FTP_SetResponseError(nResCode);
803 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
805 INTERNET_ASYNC_RESULT iar;
807 iar.dwResult = (DWORD)bSuccess;
808 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
809 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
810 &iar, sizeof(INTERNET_ASYNC_RESULT));
813 return (DWORD) bSuccess;
816 /***********************************************************************
817 * FtpOpenFileA (WININET.@)
819 * Open a remote file for writing or reading
822 * HINTERNET handle on success
826 HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
827 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
830 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
831 LPWININETAPPINFOA hIC = NULL;
833 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
835 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
839 if (lpwfs->download_in_progress != NULL) {
840 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
844 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
845 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
847 WORKREQUEST workRequest;
849 workRequest.asyncall = FTPOPENFILEA;
850 workRequest.HFTPSESSION = (DWORD)hFtpSession;
851 workRequest.LPSZFILENAME = (DWORD)FTP_strdup(lpszFileName);
852 workRequest.FDWACCESS = fdwAccess;
853 workRequest.DWFLAGS = dwFlags;
854 workRequest.DWCONTEXT = dwContext;
856 INTERNET_AsyncCall(&workRequest);
861 return FTP_FtpOpenFileA(hFtpSession, lpszFileName, fdwAccess, dwFlags, dwContext);
866 /***********************************************************************
867 * FtpOpenFileW (WININET.@)
869 * Open a remote file for writing or reading
872 * HINTERNET handle on success
876 HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession,
877 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
885 /***********************************************************************
886 * FTP_FtpOpenFileA (Internal)
888 * Open a remote file for writing or reading
891 * HINTERNET handle on success
895 HINTERNET FTP_FtpOpenFileA(HINTERNET hFtpSession,
896 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
900 BOOL bSuccess = FALSE;
901 LPWININETFILE hFile = NULL;
902 LPWININETAPPINFOA hIC = NULL;
903 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
907 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
909 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
913 /* Clear any error information */
914 INTERNET_SetLastError(0);
916 if (GENERIC_READ == fdwAccess)
918 /* Set up socket to retrieve data */
919 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
921 else if (GENERIC_WRITE == fdwAccess)
923 /* Set up socket to send data */
924 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
927 /* Get data socket to server */
928 if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
930 hFile = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFILE));
931 hFile->hdr.htype = WH_HFILE;
932 hFile->hdr.dwFlags = dwFlags;
933 hFile->hdr.dwContext = dwContext;
934 hFile->hdr.lpwhparent = hFtpSession;
935 hFile->nDataSocket = nDataSocket;
936 hFile->session_deleted = FALSE;
938 /* Indicate that a download is currently in progress */
939 lpwfs->download_in_progress = hFile;
942 if (lpwfs->lstnSocket != -1)
943 close(lpwfs->lstnSocket);
945 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
946 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
948 INTERNET_ASYNC_RESULT iar;
952 iar.dwResult = (DWORD)hFile;
953 iar.dwError = ERROR_SUCCESS;
954 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
955 &iar, sizeof(INTERNET_ASYNC_RESULT));
958 iar.dwResult = (DWORD)bSuccess;
959 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
960 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
961 &iar, sizeof(INTERNET_ASYNC_RESULT));
964 return (HINTERNET)hFile;
968 /***********************************************************************
969 * FtpGetFileA (WININET.@)
971 * Retrieve file from the FTP server
978 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
979 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
982 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hInternet;
983 LPWININETAPPINFOA hIC = NULL;
985 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
987 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
991 if (lpwfs->download_in_progress != NULL) {
992 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
996 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
997 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
999 WORKREQUEST workRequest;
1001 workRequest.asyncall = FTPGETFILEA;
1002 workRequest.HFTPSESSION = (DWORD)hInternet;
1003 workRequest.LPSZREMOTEFILE = (DWORD)FTP_strdup(lpszRemoteFile);
1004 workRequest.LPSZNEWFILE = (DWORD)FTP_strdup(lpszNewFile);
1005 workRequest.DWLOCALFLAGSATTRIBUTE = dwLocalFlagsAttribute;
1006 workRequest.FFAILIFEXISTS = (DWORD)fFailIfExists;
1007 workRequest.DWFLAGS = dwInternetFlags;
1008 workRequest.DWCONTEXT = dwContext;
1010 return INTERNET_AsyncCall(&workRequest);
1014 return FTP_FtpGetFileA(hInternet, lpszRemoteFile, lpszNewFile,
1015 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1020 /***********************************************************************
1021 * FtpGetFileW (WININET.@)
1023 * Retrieve file from the FTP server
1030 BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1031 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1039 /***********************************************************************
1040 * FTP_FtpGetFileA (Internal)
1042 * Retrieve file from the FTP server
1049 BOOL WINAPI FTP_FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1050 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1054 BOOL bSuccess = FALSE;
1056 LPWININETAPPINFOA hIC = NULL;
1057 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hInternet;
1059 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", lpszRemoteFile, lpszNewFile);
1060 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1062 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1066 /* Clear any error information */
1067 INTERNET_SetLastError(0);
1069 /* Ensure we can write to lpszNewfile by opening it */
1070 hFile = CreateFileA(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
1071 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
1072 if (INVALID_HANDLE_VALUE == hFile)
1075 /* Set up socket to retrieve data */
1076 nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags);
1082 /* Get data socket to server */
1083 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
1088 FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile);
1089 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1090 MAX_REPLY_LEN, 0, 0, 0);
1093 if (nResCode == 226)
1096 FTP_SetResponseError(nResCode);
1103 if (lpwfs->lstnSocket != -1)
1104 close(lpwfs->lstnSocket);
1109 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1110 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1112 INTERNET_ASYNC_RESULT iar;
1114 iar.dwResult = (DWORD)bSuccess;
1115 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1116 hIC->lpfnStatusCB(hInternet, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1117 &iar, sizeof(INTERNET_ASYNC_RESULT));
1124 /***********************************************************************
1125 * FtpDeleteFileA (WININET.@)
1127 * Delete a file on the ftp server
1134 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1136 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1137 LPWININETAPPINFOA hIC = NULL;
1139 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1141 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1145 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1146 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1148 WORKREQUEST workRequest;
1150 workRequest.asyncall = FTPRENAMEFILEA;
1151 workRequest.HFTPSESSION = (DWORD)hFtpSession;
1152 workRequest.LPSZFILENAME = (DWORD)FTP_strdup(lpszFileName);
1154 return INTERNET_AsyncCall(&workRequest);
1158 return FTP_FtpDeleteFileA(hFtpSession, lpszFileName);
1163 /***********************************************************************
1164 * FTP_FtpDeleteFileA (Internal)
1166 * Delete a file on the ftp server
1173 BOOL FTP_FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1176 BOOL bSuccess = FALSE;
1177 LPWININETAPPINFOA hIC = NULL;
1178 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1180 TRACE("0x%08lx\n", (ULONG) hFtpSession);
1181 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1183 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1187 /* Clear any error information */
1188 INTERNET_SetLastError(0);
1190 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1193 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1194 MAX_REPLY_LEN, 0, 0, 0);
1197 if (nResCode == 250)
1200 FTP_SetResponseError(nResCode);
1203 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1204 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1206 INTERNET_ASYNC_RESULT iar;
1208 iar.dwResult = (DWORD)bSuccess;
1209 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1210 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1211 &iar, sizeof(INTERNET_ASYNC_RESULT));
1218 /***********************************************************************
1219 * FtpRemoveDirectoryA (WININET.@)
1221 * Remove a directory on the ftp server
1228 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1230 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1231 LPWININETAPPINFOA hIC = NULL;
1233 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1235 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1239 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1240 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1242 WORKREQUEST workRequest;
1244 workRequest.asyncall = FTPREMOVEDIRECTORYA;
1245 workRequest.HFTPSESSION = (DWORD)hFtpSession;
1246 workRequest.LPSZDIRECTORY = (DWORD)FTP_strdup(lpszDirectory);
1248 return INTERNET_AsyncCall(&workRequest);
1252 return FTP_FtpRemoveDirectoryA(hFtpSession, lpszDirectory);
1257 /***********************************************************************
1258 * FTP_FtpRemoveDirectoryA (Internal)
1260 * Remove a directory on the ftp server
1267 BOOL FTP_FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1270 BOOL bSuccess = FALSE;
1271 LPWININETAPPINFOA hIC = NULL;
1272 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1275 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1277 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1281 /* Clear any error information */
1282 INTERNET_SetLastError(0);
1284 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1287 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1288 MAX_REPLY_LEN, 0, 0, 0);
1291 if (nResCode == 250)
1294 FTP_SetResponseError(nResCode);
1298 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1299 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1301 INTERNET_ASYNC_RESULT iar;
1303 iar.dwResult = (DWORD)bSuccess;
1304 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1305 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1306 &iar, sizeof(INTERNET_ASYNC_RESULT));
1313 /***********************************************************************
1314 * FtpRenameFileA (WININET.@)
1316 * Rename a file on the ftp server
1323 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1325 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1326 LPWININETAPPINFOA hIC = NULL;
1328 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1330 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1334 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1335 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1337 WORKREQUEST workRequest;
1339 workRequest.asyncall = FTPRENAMEFILEA;
1340 workRequest.HFTPSESSION = (DWORD)hFtpSession;
1341 workRequest.LPSZSRCFILE = (DWORD)FTP_strdup(lpszSrc);
1342 workRequest.LPSZDESTFILE = (DWORD)FTP_strdup(lpszDest);
1344 return INTERNET_AsyncCall(&workRequest);
1348 return FTP_FtpRenameFileA(hFtpSession, lpszSrc, lpszDest);
1352 /***********************************************************************
1353 * FTP_FtpRenameFileA (Internal)
1355 * Rename a file on the ftp server
1362 BOOL FTP_FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1365 BOOL bSuccess = FALSE;
1366 LPWININETAPPINFOA hIC = NULL;
1367 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1370 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1372 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1376 /* Clear any error information */
1377 INTERNET_SetLastError(0);
1379 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1382 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket,
1383 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1384 if (nResCode == 350)
1386 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1389 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket,
1390 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1393 if (nResCode == 250)
1396 FTP_SetResponseError(nResCode);
1399 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1400 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1402 INTERNET_ASYNC_RESULT iar;
1404 iar.dwResult = (DWORD)bSuccess;
1405 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1406 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1407 &iar, sizeof(INTERNET_ASYNC_RESULT));
1414 /***********************************************************************
1415 * FTP_Connect (internal)
1417 * Connect to a ftp server
1420 * HINTERNET a session handle on success
1425 HINTERNET FTP_Connect(HINTERNET hInternet, LPCSTR lpszServerName,
1426 INTERNET_PORT nServerPort, LPCSTR lpszUserName,
1427 LPCSTR lpszPassword, DWORD dwFlags, DWORD dwContext)
1429 struct sockaddr_in socketAddr;
1430 struct hostent *phe = NULL;
1431 INT nsocket = -1, sock_namelen;
1432 LPWININETAPPINFOA hIC = NULL;
1433 BOOL bSuccess = FALSE;
1434 LPWININETFTPSESSIONA lpwfs = NULL;
1436 TRACE("0x%08lx Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1437 (ULONG) hInternet, lpszServerName,
1438 nServerPort, lpszUserName, lpszPassword);
1440 if (((LPWININETHANDLEHEADER)hInternet)->htype != WH_HINIT)
1443 hIC = (LPWININETAPPINFOA) hInternet;
1445 if (NULL == lpszUserName && NULL != lpszPassword)
1447 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_USER_NAME);
1451 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1452 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1454 if (hIC->lpfnStatusCB)
1455 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1456 (LPSTR) lpszServerName, strlen(lpszServerName));
1458 if (!GetAddress(lpszServerName, nServerPort, &phe, &socketAddr))
1460 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1464 if (hIC->lpfnStatusCB)
1465 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1466 (LPSTR) lpszServerName, strlen(lpszServerName));
1468 nsocket = socket(AF_INET,SOCK_STREAM,0);
1471 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1475 if (hIC->lpfnStatusCB)
1476 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1477 &socketAddr, sizeof(struct sockaddr_in));
1479 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1481 ERR("Unable to connect (%s)\n", strerror(errno));
1482 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1486 TRACE("Connected to server\n");
1487 if (hIC->lpfnStatusCB)
1488 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1489 &socketAddr, sizeof(struct sockaddr_in));
1491 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONA));
1494 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1498 lpwfs->hdr.htype = WH_HFTPSESSION;
1499 lpwfs->hdr.dwFlags = dwFlags;
1500 lpwfs->hdr.dwContext = dwContext;
1501 lpwfs->hdr.lpwhparent = (LPWININETHANDLEHEADER)hInternet;
1502 lpwfs->sndSocket = nsocket;
1503 lpwfs->download_in_progress = NULL;
1504 sock_namelen = sizeof(lpwfs->socketAddress);
1505 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
1506 lpwfs->phostent = phe;
1508 if (NULL == lpszUserName)
1510 lpwfs->lpszUserName = FTP_strdup("anonymous");
1511 lpwfs->lpszPassword = FTP_strdup("user@server");
1515 lpwfs->lpszUserName = FTP_strdup(lpszUserName);
1516 lpwfs->lpszPassword = FTP_strdup(lpszPassword);
1519 if (FTP_ConnectToHost(lpwfs))
1521 if (hIC->lpfnStatusCB)
1523 INTERNET_ASYNC_RESULT iar;
1525 iar.dwResult = (DWORD)lpwfs;
1526 iar.dwError = ERROR_SUCCESS;
1528 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_HANDLE_CREATED,
1529 &iar, sizeof(INTERNET_ASYNC_RESULT));
1531 TRACE("Successfully logged into server\n");
1537 if (!bSuccess && nsocket == -1)
1540 if (!bSuccess && lpwfs)
1542 HeapFree(GetProcessHeap(), 0, lpwfs);
1546 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1548 INTERNET_ASYNC_RESULT iar;
1550 iar.dwResult = (DWORD)lpwfs;
1551 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1552 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1553 &iar, sizeof(INTERNET_ASYNC_RESULT));
1556 return (HINTERNET) lpwfs;
1560 /***********************************************************************
1561 * FTP_ConnectToHost (internal)
1563 * Connect to a ftp server
1570 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs)
1573 BOOL bSuccess = FALSE;
1576 FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1578 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
1581 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1582 MAX_REPLY_LEN, 0, 0, 0);
1585 /* Login successful... */
1586 if (nResCode == 230)
1588 /* User name okay, need password... */
1589 else if (nResCode == 331)
1590 bSuccess = FTP_SendPassword(lpwfs);
1591 /* Need account for login... */
1592 else if (nResCode == 332)
1593 bSuccess = FTP_SendAccount(lpwfs);
1595 FTP_SetResponseError(nResCode);
1598 TRACE("Returning %d\n", bSuccess);
1604 /***********************************************************************
1605 * FTP_SendCommand (internal)
1607 * Send command to server
1614 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
1615 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1619 DWORD nBytesSent = 0;
1623 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
1626 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1628 bParamHasLen = lpszParam && strlen(lpszParam) > 0;
1629 len = (bParamHasLen ? strlen(lpszParam) : -1) + strlen(szFtpCommands[ftpCmd]) +
1631 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
1633 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1636 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], bParamHasLen ? " " : "",
1637 bParamHasLen ? lpszParam : "", szCRLF);
1639 TRACE("Sending (%s) len(%ld)\n", buf, len);
1640 while((nBytesSent < len) && (nRC != -1))
1642 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
1646 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
1649 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_REQUEST_SENT,
1650 &nBytesSent, sizeof(DWORD));
1652 TRACE("Sent %ld bytes\n", nBytesSent);
1657 /***********************************************************************
1658 * FTP_ReceiveResponse (internal)
1660 * Receive response from server
1663 * Reply code on success
1668 INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse,
1669 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1673 char firstprefix[5];
1674 BOOL multiline = FALSE;
1677 TRACE("socket(%d) \n", nSocket);
1680 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1685 if (!INTERNET_GetNextLine(nSocket, lpszResponse, &nRecv))
1692 if(lpszResponse[3] != '-')
1695 { /* Start of multiline repsonse. Loop until we get "nnn " */
1697 memcpy(firstprefix, lpszResponse, 3);
1698 firstprefix[3] = ' ';
1699 firstprefix[4] = '\0';
1704 if(!memcmp(firstprefix, lpszResponse, 4))
1712 rc = atoi(lpszResponse);
1715 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
1716 &nRecv, sizeof(DWORD));
1720 TRACE("return %d\n", rc);
1725 /***********************************************************************
1726 * FTP_SendPassword (internal)
1728 * Send password to ftp server
1735 BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs)
1738 BOOL bSuccess = FALSE;
1741 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
1744 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1745 MAX_REPLY_LEN, 0, 0, 0);
1748 TRACE("Received reply code %d\n", nResCode);
1749 /* Login successful... */
1750 if (nResCode == 230)
1752 /* Command not implemented, superfluous at the server site... */
1753 /* Need account for login... */
1754 else if (nResCode == 332)
1755 bSuccess = FTP_SendAccount(lpwfs);
1757 FTP_SetResponseError(nResCode);
1761 TRACE("Returning %d\n", bSuccess);
1766 /***********************************************************************
1767 * FTP_SendAccount (internal)
1776 BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs)
1779 BOOL bSuccess = FALSE;
1782 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, NOACCOUNT, 0, 0, 0))
1785 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1786 MAX_REPLY_LEN, 0, 0, 0);
1790 FTP_SetResponseError(nResCode);
1797 /***********************************************************************
1798 * FTP_SendStore (internal)
1800 * Send request to upload file to ftp server
1807 BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
1810 BOOL bSuccess = FALSE;
1813 if (!FTP_InitListenSocket(lpwfs))
1816 if (!FTP_SendType(lpwfs, dwType))
1819 if (!FTP_SendPortOrPasv(lpwfs))
1822 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
1824 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1825 MAX_REPLY_LEN, 0, 0, 0);
1828 if (nResCode == 150)
1831 FTP_SetResponseError(nResCode);
1835 if (!bSuccess && lpwfs->lstnSocket != -1)
1837 close(lpwfs->lstnSocket);
1838 lpwfs->lstnSocket = -1;
1845 /***********************************************************************
1846 * FTP_InitListenSocket (internal)
1848 * Create a socket to listen for server response
1855 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs)
1857 BOOL bSuccess = FALSE;
1858 size_t namelen = sizeof(struct sockaddr_in);
1862 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
1863 if (lpwfs->lstnSocket == -1)
1865 TRACE("Unable to create listening socket\n");
1869 /* We obtain our ip addr from the name of the command channel socket */
1870 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
1872 /* and get the system to assign us a port */
1873 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
1875 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
1877 TRACE("Unable to bind socket\n");
1881 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
1883 TRACE("listen failed\n");
1887 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
1891 if (!bSuccess && lpwfs->lstnSocket == -1)
1893 close(lpwfs->lstnSocket);
1894 lpwfs->lstnSocket = -1;
1901 /***********************************************************************
1902 * FTP_SendType (internal)
1904 * Tell server type of data being transferred
1910 * W98SE doesn't cache the type that's currently set
1911 * (i.e. it sends it always),
1912 * so we probably don't want to do that either.
1914 BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType)
1917 CHAR type[2] = { "I" };
1918 BOOL bSuccess = FALSE;
1921 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
1924 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
1927 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1928 MAX_REPLY_LEN, 0, 0, 0)/100;
1934 FTP_SetResponseError(nResCode);
1941 /***********************************************************************
1942 * FTP_GetFileSize (internal)
1944 * Retrieves from the server the size of the given file
1951 BOOL FTP_GetFileSize(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD *dwSize)
1954 BOOL bSuccess = FALSE;
1958 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
1961 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1962 MAX_REPLY_LEN, 0, 0, 0);
1965 if (nResCode == 213) {
1966 /* Now parses the output to get the actual file size */
1968 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
1970 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
1971 if (lpszResponseBuffer[i] == '\0') return FALSE;
1972 *dwSize = atol(&(lpszResponseBuffer[i + 1]));
1976 FTP_SetResponseError(nResCode);
1985 /***********************************************************************
1986 * FTP_SendPort (internal)
1988 * Tell server which port to use
1995 BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs)
1998 CHAR szIPAddress[64];
1999 BOOL bSuccess = FALSE;
2002 sprintf(szIPAddress, "%d,%d,%d,%d,%d,%d",
2003 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2004 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2005 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2006 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2007 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2008 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2010 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2013 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2014 MAX_REPLY_LEN,0, 0, 0);
2017 if (nResCode == 200)
2020 FTP_SetResponseError(nResCode);
2028 /***********************************************************************
2029 * FTP_DoPassive (internal)
2031 * Tell server that we want to do passive transfers
2032 * and connect data socket
2039 BOOL FTP_DoPassive(LPWININETFTPSESSIONA lpwfs)
2042 BOOL bSuccess = FALSE;
2045 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2048 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2049 MAX_REPLY_LEN,0, 0, 0);
2052 if (nResCode == 227)
2054 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2058 char *pAddr, *pPort;
2060 struct sockaddr_in dataSocketAddress;
2062 p = lpszResponseBuffer+4; /* skip status code */
2064 /* do a very strict check; we can improve that later. */
2066 if (strncmp(p, "Entering Passive Mode", 21))
2068 ERR("unknown response '%.*s', aborting\n", 21, p);
2071 p += 21; /* skip string */
2072 if ((*p++ != ' ') || (*p++ != '('))
2074 ERR("unknown response format, aborting\n");
2078 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2081 ERR("unknown response address format '%s', aborting\n", p);
2084 for (i=0; i < 6; i++)
2087 dataSocketAddress = lpwfs->socketAddress;
2088 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2089 pPort = (char *)&(dataSocketAddress.sin_port);
2097 nsocket = socket(AF_INET,SOCK_STREAM,0);
2101 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2103 ERR("can't connect passive FTP data port.\n");
2106 lpwfs->pasvSocket = nsocket;
2110 FTP_SetResponseError(nResCode);
2118 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs)
2120 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2122 if (!FTP_DoPassive(lpwfs))
2127 if (!FTP_SendPort(lpwfs))
2134 /***********************************************************************
2135 * FTP_GetDataSocket (internal)
2137 * Either accepts an incoming data socket connection from the server
2138 * or just returns the already opened socket after a PASV command
2139 * in case of passive FTP.
2147 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket)
2149 struct sockaddr_in saddr;
2150 size_t addrlen = sizeof(struct sockaddr);
2153 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2155 *nDataSocket = lpwfs->pasvSocket;
2159 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2160 close(lpwfs->lstnSocket);
2161 lpwfs->lstnSocket = -1;
2163 return *nDataSocket != -1;
2167 /***********************************************************************
2168 * FTP_SendData (internal)
2170 * Send data to the server
2177 BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile)
2179 BY_HANDLE_FILE_INFORMATION fi;
2180 DWORD nBytesRead = 0;
2181 DWORD nBytesSent = 0;
2182 DWORD nTotalSent = 0;
2183 DWORD nBytesToSend, nLen, nRC = 1;
2184 time_t s_long_time, e_long_time;
2189 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2190 memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2192 /* Get the size of the file. */
2193 GetFileInformationByHandle(hFile, &fi);
2198 nBytesToSend = nBytesRead - nBytesSent;
2200 if (nBytesToSend <= 0)
2202 /* Read data from file. */
2204 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2205 ERR("Failed reading from file\n");
2208 nBytesToSend = nBytesRead;
2213 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2214 DATA_PACKET_SIZE : nBytesToSend;
2215 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2223 /* Do some computation to display the status. */
2225 nSeconds = e_long_time - s_long_time;
2226 if( nSeconds / 60 > 0 )
2228 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld min %ld sec estimated remainig time %ld sec\n",
2229 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2230 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2234 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld sec estimated remainig time %ld sec\n",
2235 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2236 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2238 } while (nRC != -1);
2240 TRACE("file transfer complete!\n");
2242 if(lpszBuffer != NULL)
2243 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2249 /***********************************************************************
2250 * FTP_SendRetrieve (internal)
2252 * Send request to retrieve a file
2255 * Number of bytes to be received on success
2259 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
2265 if (!FTP_InitListenSocket(lpwfs))
2268 if (!FTP_SendType(lpwfs, dwType))
2271 if (!FTP_SendPortOrPasv(lpwfs))
2274 if (!FTP_GetFileSize(lpwfs, lpszRemoteFile, &nResult))
2277 TRACE("Waiting to receive %ld bytes\n", nResult);
2279 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2282 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2283 MAX_REPLY_LEN, 0, 0, 0);
2284 if ((nResCode != 125) && (nResCode != 150)) {
2285 /* That means that we got an error getting the file. */
2290 if (0 == nResult && lpwfs->lstnSocket != -1)
2292 close(lpwfs->lstnSocket);
2293 lpwfs->lstnSocket = -1;
2300 /***********************************************************************
2301 * FTP_RetrieveData (internal)
2303 * Retrieve data from server
2310 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2312 DWORD nBytesWritten;
2313 DWORD nBytesReceived = 0;
2319 if (INVALID_HANDLE_VALUE == hFile)
2322 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2323 if (NULL == lpszBuffer)
2325 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2329 while (nBytesReceived < nBytes && nRC != -1)
2331 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2334 /* other side closed socket. */
2337 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2338 nBytesReceived += nRC;
2341 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived, nBytes,
2342 nBytesReceived * 100 / nBytes);
2345 TRACE("Data transfer complete\n");
2346 if (NULL != lpszBuffer)
2347 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2354 /***********************************************************************
2355 * FTP_CloseSessionHandle (internal)
2357 * Deallocate session handle
2364 BOOL FTP_CloseSessionHandle(LPWININETFTPSESSIONA lpwfs)
2368 if (lpwfs->download_in_progress != NULL)
2369 lpwfs->download_in_progress->session_deleted = TRUE;
2371 if (lpwfs->sndSocket != -1)
2372 close(lpwfs->sndSocket);
2374 if (lpwfs->lstnSocket != -1)
2375 close(lpwfs->lstnSocket);
2377 if (lpwfs->lpszPassword)
2378 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2380 if (lpwfs->lpszUserName)
2381 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2383 HeapFree(GetProcessHeap(), 0, lpwfs);
2389 /***********************************************************************
2390 * FTP_CloseFindNextHandle (internal)
2392 * Deallocate session handle
2399 BOOL FTP_CloseFindNextHandle(LPWININETFINDNEXTA lpwfn)
2405 for (i = 0; i < lpwfn->size; i++)
2407 if (NULL != lpwfn->lpafp[i].lpszName)
2408 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2411 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2412 HeapFree(GetProcessHeap(), 0, lpwfn);
2417 /***********************************************************************
2418 * FTP_CloseFileTransferHandle (internal)
2420 * Closes the file transfer handle. This also 'cleans' the data queue of
2421 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2428 BOOL FTP_CloseFileTransferHandle(LPWININETFILE lpwh)
2430 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) lpwh->hdr.lpwhparent;
2435 if (!lpwh->session_deleted)
2436 lpwfs->download_in_progress = NULL;
2438 /* This just serves to flush the control socket of any spurrious lines written
2439 to it (like '226 Transfer complete.').
2441 Wonder what to do if the server sends us an error code though...
2443 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2444 MAX_REPLY_LEN, 0, 0, 0);
2446 if (lpwh->nDataSocket != -1)
2447 close(lpwh->nDataSocket);
2449 HeapFree(GetProcessHeap(), 0, lpwh);
2454 /***********************************************************************
2455 * FTP_ReceiveFileList (internal)
2457 * Read file list from server
2460 * Handle to file list on success
2464 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket,
2465 LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext)
2468 LPFILEPROPERTIESA lpafp = NULL;
2469 LPWININETFINDNEXTA lpwfn = NULL;
2473 if (FTP_ParseDirectory(lpwfs, nSocket, &lpafp, &dwSize))
2475 FTP_ConvertFileProp(lpafp, lpFindFileData);
2477 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFINDNEXTA));
2480 lpwfn->hdr.htype = WH_HFINDNEXT;
2481 lpwfn->hdr.lpwhparent = (LPWININETHANDLEHEADER)lpwfs;
2482 lpwfn->hdr.dwContext = dwContext;
2483 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
2484 lpwfn->size = dwSize;
2485 lpwfn->lpafp = lpafp;
2489 TRACE("Matched %ld files\n", dwSize);
2490 return (HINTERNET)lpwfn;
2494 /***********************************************************************
2495 * FTP_ConvertFileProp (internal)
2497 * Converts FILEPROPERTIESA struct to WIN32_FIND_DATAA
2504 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESA lpafp, LPWIN32_FIND_DATAA lpFindFileData)
2506 BOOL bSuccess = FALSE;
2508 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
2512 /* Convert 'Unix' time to Windows time */
2513 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
2514 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
2516 /* Not all fields are filled in */
2517 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
2518 lpFindFileData->nFileSizeLow = lpafp->nSize;
2520 if (lpafp->bIsDirectory)
2521 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
2523 if (lpafp->lpszName)
2524 strncpy(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
2533 /***********************************************************************
2534 * FTP_ParseDirectory (internal)
2536 * Parse string of directory information
2542 * FIXME: - This function needs serious clea-up
2543 * - We should consider both UNIX and NT list formats
2545 #define MAX_MONTH_LEN 10
2546 #define MIN_LEN_DIR_ENTRY 15
2548 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp)
2551 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2554 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2560 CHAR pszMonth[MAX_MONTH_LEN];
2562 BOOL bSuccess = TRUE;
2563 DWORD nBufLen = MAX_REPLY_LEN;
2564 LPFILEPROPERTIESA curFileProp = NULL;
2565 CHAR* pszLine = NULL;
2566 CHAR* pszToken = NULL;
2567 INT nTokenToSkip = 3;
2575 INT sizeFilePropArray = 20;
2576 INT indexFilePropArray = 0;
2580 /* Allocate intial file properties array */
2581 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESA)*(sizeFilePropArray));
2588 while ((pszLine = INTERNET_GetNextLine(nSocket, INTERNET_GetResponseBuffer(), &nBufLen)) != NULL)
2590 if (sizeFilePropArray <= indexFilePropArray)
2592 LPFILEPROPERTIESA tmpafp;
2594 sizeFilePropArray *= 2;
2595 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
2596 sizeof(FILEPROPERTIESA)*sizeFilePropArray);
2606 curFileProp = &((*lpafp)[indexFilePropArray]);
2608 /* First Parse the permissions. */
2609 pszToken = strtok(pszLine, " \t" );
2611 /* HACK! If this is not a file listing skip the line */
2612 if (!pszToken || nBufLen <= MIN_LEN_DIR_ENTRY)
2614 nBufLen = MAX_REPLY_LEN;
2617 if (10 == strlen(pszToken)) {
2618 /* Unix way of parsing ... */
2619 FTP_ParsePermission(pszToken, curFileProp);
2624 pszToken = strtok( NULL, " \t" );
2626 } while( nCount <= nTokenToSkip );
2628 /* Store the size of the file in the param list. */
2629 TRACE("nSize-> %s\n", pszToken);
2630 if (pszToken != NULL)
2631 curFileProp->nSize = atol(pszToken);
2633 /* Parse last modified time. */
2641 pszToken = strtok( NULL, " \t" );
2642 strncpy(pszMonth, pszToken, MAX_MONTH_LEN);
2643 CharUpperA(pszMonth);
2644 pszMatch = strstr(szMonths, pszMonth);
2645 if( pszMatch != NULL )
2646 nMonth = (pszMatch - szMonths) / 3;
2648 pszToken = strtok(NULL, " \t");
2649 TRACE("nDay -> %s\n", pszToken);
2650 if (pszToken != NULL)
2651 nDay = atoi(pszToken);
2653 pszToken = strtok(NULL, " \t");
2654 pszMinutes = strchr(pszToken, ':');
2655 if( pszMinutes != NULL ) {
2657 nMinutes = atoi(pszMinutes);
2658 pszHour = pszMinutes - 3;
2659 if (pszHour != NULL)
2660 nHour = atoi(pszHour);
2662 apTM = localtime( &aTime );
2663 nYear = apTM->tm_year;
2665 nYear = atoi(pszToken);
2670 curFileProp->tmLastModified.tm_sec = nSeconds;
2671 curFileProp->tmLastModified.tm_min = nMinutes;
2672 curFileProp->tmLastModified.tm_hour = nHour;
2673 curFileProp->tmLastModified.tm_mday = nDay;
2674 curFileProp->tmLastModified.tm_mon = nMonth;
2675 curFileProp->tmLastModified.tm_year = nYear;
2677 pszToken = strtok(NULL, " \t");
2678 if(pszToken != NULL) {
2679 curFileProp->lpszName = FTP_strdup(pszToken);
2680 TRACE(": %s\n", curFileProp->lpszName);
2683 nBufLen = MAX_REPLY_LEN;
2684 indexFilePropArray++;
2685 } else if (8 == strlen(pszToken)) {
2686 /* NT way of parsing ... :
2688 07-13-03 08:55PM <DIR> sakpatch
2689 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
2692 curFileProp->permissions = 0xFFFF; /* No idea, put full permission :-) */
2694 sscanf(pszToken, "%d-%d-%d",
2695 &curFileProp->tmLastModified.tm_mon,
2696 &curFileProp->tmLastModified.tm_mday,
2697 &curFileProp->tmLastModified.tm_year);
2699 /* Hacky and bad Y2K protection :-) */
2700 if (curFileProp->tmLastModified.tm_year < 70)
2701 curFileProp->tmLastModified.tm_year += 100;
2703 pszToken = strtok(NULL, " \t");
2704 if (pszToken == NULL) {
2705 nBufLen = MAX_REPLY_LEN;
2708 sscanf(pszToken, "%d:%d",
2709 &curFileProp->tmLastModified.tm_hour,
2710 &curFileProp->tmLastModified.tm_min);
2711 if ((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
2712 curFileProp->tmLastModified.tm_hour += 12;
2714 curFileProp->tmLastModified.tm_sec = 0;
2716 TRACE("Mod time: %2d:%2d:%2d %2d/%2d/%2d\n",
2717 curFileProp->tmLastModified.tm_hour, curFileProp->tmLastModified.tm_min, curFileProp->tmLastModified.tm_sec,
2718 (curFileProp->tmLastModified.tm_year >= 100) ? curFileProp->tmLastModified.tm_year - 100 : curFileProp->tmLastModified.tm_year,
2719 curFileProp->tmLastModified.tm_mon, curFileProp->tmLastModified.tm_mday);
2721 pszToken = strtok(NULL, " \t");
2722 if (pszToken == NULL) {
2723 nBufLen = MAX_REPLY_LEN;
2726 if (!strcasecmp(pszToken, "<DIR>")) {
2727 curFileProp->bIsDirectory = TRUE;
2728 TRACE("Is directory\n");
2730 curFileProp->bIsDirectory = FALSE;
2731 curFileProp->nSize = atol(pszToken);
2732 TRACE("nSize: %ld\n", curFileProp->nSize);
2735 pszToken = strtok(NULL, " \t");
2736 if (pszToken == NULL) {
2737 nBufLen = MAX_REPLY_LEN;
2740 curFileProp->lpszName = FTP_strdup(pszToken);
2741 TRACE("Name: %s\n", curFileProp->lpszName);
2743 nBufLen = MAX_REPLY_LEN;
2744 indexFilePropArray++;
2746 nBufLen = MAX_REPLY_LEN;
2750 if (bSuccess && indexFilePropArray)
2752 if (indexFilePropArray < sizeFilePropArray - 1)
2754 LPFILEPROPERTIESA tmpafp;
2756 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
2757 sizeof(FILEPROPERTIESA)*indexFilePropArray);
2761 *dwfp = indexFilePropArray;
2765 HeapFree(GetProcessHeap(), 0, *lpafp);
2766 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2775 /***********************************************************************
2776 * FTP_ParsePermission (internal)
2778 * Parse permission string of directory information
2785 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp)
2787 BOOL bSuccess = TRUE;
2788 unsigned short nPermission = 0;
2793 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
2799 lpfp->bIsDirectory = (*lpszPermission == 'd');
2805 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
2808 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
2811 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
2814 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
2817 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
2820 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
2823 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
2826 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
2829 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
2833 }while (nPos <= nLast);
2835 lpfp->permissions = nPermission;
2840 /***********************************************************************
2841 * FTP_SetResponseError (internal)
2843 * Set the appropriate error code for a given response from the server
2848 DWORD FTP_SetResponseError(DWORD dwResponse)
2854 case 421: /* Service not available - Server may be shutting down. */
2855 dwCode = ERROR_INTERNET_TIMEOUT;
2858 case 425: /* Cannot open data connection. */
2859 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
2862 case 426: /* Connection closed, transer aborted. */
2863 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
2866 case 500: /* Syntax error. Command unrecognized. */
2867 case 501: /* Syntax error. Error in parameters or arguments. */
2868 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
2871 case 530: /* Not logged in. Login incorrect. */
2872 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
2875 case 550: /* File action not taken. File not found or no access. */
2876 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
2879 case 450: /* File action not taken. File may be busy. */
2880 case 451: /* Action aborted. Server error. */
2881 case 452: /* Action not taken. Insufficient storage space on server. */
2882 case 502: /* Command not implemented. */
2883 case 503: /* Bad sequence of command. */
2884 case 504: /* Command not implemented for that parameter. */
2885 case 532: /* Need account for storing files */
2886 case 551: /* Requested action aborted. Page type unknown */
2887 case 552: /* Action aborted. Exceeded storage allocation */
2888 case 553: /* Action not taken. File name not allowed. */
2891 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
2895 INTERNET_SetLastError(dwCode);