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>
50 #include "wine/debug.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
55 #define NOACCOUNT "noaccount"
56 #define DATA_PACKET_SIZE 0x2000
61 /* FTP commands with arguments. */
76 /* FTP commands without arguments. */
85 static const CHAR *szFtpCommands[] = {
107 static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
109 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
110 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
111 BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType);
112 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket);
113 BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile);
114 INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse,
115 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
116 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType);
117 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile);
118 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs);
119 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs);
120 BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs);
121 BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs);
122 BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType);
123 BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs);
124 BOOL FTP_DoPassive(LPWININETFTPSESSIONA lpwfs);
125 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs);
126 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp);
127 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp);
128 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket,
129 LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext);
130 DWORD FTP_SetResponseError(DWORD dwResponse);
132 inline static LPSTR FTP_strdup( LPCSTR str )
134 LPSTR ret = HeapAlloc( GetProcessHeap(), 0, strlen(str) + 1 );
135 if (ret) strcpy( ret, str );
139 /***********************************************************************
140 * FtpPutFileA (WININET.@)
142 * Uploads a file to the FTP server
149 BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
150 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
152 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
153 LPWININETAPPINFOA hIC = NULL;
155 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
157 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
161 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
162 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
164 WORKREQUEST workRequest;
166 workRequest.asyncall = FTPPUTFILEA;
167 workRequest.HFTPSESSION = (DWORD)hConnect;
168 workRequest.LPSZLOCALFILE = (DWORD)FTP_strdup(lpszLocalFile);
169 workRequest.LPSZNEWREMOTEFILE = (DWORD)FTP_strdup(lpszNewRemoteFile);
170 workRequest.DWFLAGS = dwFlags;
171 workRequest.DWCONTEXT = dwContext;
173 return INTERNET_AsyncCall(&workRequest);
177 return FTP_FtpPutFileA(hConnect, lpszLocalFile,
178 lpszNewRemoteFile, dwFlags, dwContext);
182 /***********************************************************************
183 * FTP_FtpPutFileA (Internal)
185 * Uploads a file to the FTP server
192 BOOL WINAPI FTP_FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
193 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
196 BOOL bSuccess = FALSE;
197 LPWININETAPPINFOA hIC = NULL;
198 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
201 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", lpszLocalFile, lpszNewRemoteFile);
202 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
204 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
208 /* Clear any error information */
209 INTERNET_SetLastError(0);
211 /* Open file to be uploaded */
212 if (INVALID_HANDLE_VALUE ==
213 (hFile = CreateFileA(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
215 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND);
219 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
220 if (hIC->lpfnStatusCB)
221 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
223 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
227 /* Get data socket to server */
228 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
230 FTP_SendData(lpwfs, nDataSocket, hFile);
232 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
233 MAX_REPLY_LEN, 0, 0, 0);
239 FTP_SetResponseError(nResCode);
245 if (lpwfs->lstnSocket != -1)
246 close(lpwfs->lstnSocket);
248 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
250 INTERNET_ASYNC_RESULT iar;
252 iar.dwResult = (DWORD)bSuccess;
253 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
254 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
255 &iar, sizeof(INTERNET_ASYNC_RESULT));
265 /***********************************************************************
266 * FtpSetCurrentDirectoryA (WININET.@)
268 * Change the working directory on the FTP server
275 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
277 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
278 LPWININETAPPINFOA hIC = NULL;
280 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
282 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
286 TRACE("lpszDirectory(%s)\n", lpszDirectory);
288 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
289 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
291 WORKREQUEST workRequest;
293 workRequest.asyncall = FTPSETCURRENTDIRECTORYA;
294 workRequest.HFTPSESSION = (DWORD)hConnect;
295 workRequest.LPSZDIRECTORY = (DWORD)FTP_strdup(lpszDirectory);
297 return INTERNET_AsyncCall(&workRequest);
301 return FTP_FtpSetCurrentDirectoryA(hConnect, lpszDirectory);
306 /***********************************************************************
307 * FtpSetCurrentDirectoryW (WININET.@)
309 * Change the working directory on the FTP server
316 BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
322 len = lstrlenW(lpszDirectory)+1;
323 if (!(szDir = (CHAR *)malloc(len*sizeof(CHAR))))
325 WideCharToMultiByte(CP_ACP, -1, lpszDirectory, -1, szDir, len, NULL, NULL);
326 rc = FtpSetCurrentDirectoryA(hConnect, szDir);
333 /***********************************************************************
334 * FTP_FtpSetCurrentDirectoryA (Internal)
336 * Change the working directory on the FTP server
343 BOOL WINAPI FTP_FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
346 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
347 LPWININETAPPINFOA hIC = NULL;
348 DWORD bSuccess = FALSE;
350 TRACE("lpszDirectory(%s)\n", lpszDirectory);
352 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
354 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
358 /* Clear any error information */
359 INTERNET_SetLastError(0);
361 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
362 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
363 hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
366 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
367 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
374 FTP_SetResponseError(nResCode);
378 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
380 INTERNET_ASYNC_RESULT iar;
382 iar.dwResult = (DWORD)bSuccess;
383 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
384 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
385 &iar, sizeof(INTERNET_ASYNC_RESULT));
391 /***********************************************************************
392 * FtpCreateDirectoryA (WININET.@)
394 * Create new directory on the FTP server
401 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
403 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
404 LPWININETAPPINFOA hIC = NULL;
406 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
408 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
412 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
413 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
415 WORKREQUEST workRequest;
417 workRequest.asyncall = FTPCREATEDIRECTORYA;
418 workRequest.HFTPSESSION = (DWORD)hConnect;
419 workRequest.LPSZDIRECTORY = (DWORD)FTP_strdup(lpszDirectory);
421 return INTERNET_AsyncCall(&workRequest);
425 return FTP_FtpCreateDirectoryA(hConnect, lpszDirectory);
430 /***********************************************************************
431 * FtpCreateDirectoryW (WININET.@)
433 * Create new directory on the FTP server
440 BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
446 len = lstrlenW(lpszDirectory)+1;
447 if (!(szDir = (CHAR *)malloc(len*sizeof(CHAR))))
449 WideCharToMultiByte(CP_ACP, -1, lpszDirectory, -1, szDir, len, NULL, NULL);
450 rc = FtpCreateDirectoryA(hConnect, szDir);
457 /***********************************************************************
458 * FTP_FtpCreateDirectoryA (Internal)
460 * Create new directory on the FTP server
467 BOOL WINAPI FTP_FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
470 BOOL bSuccess = FALSE;
471 LPWININETAPPINFOA hIC = NULL;
472 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
475 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
477 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
481 /* Clear any error information */
482 INTERNET_SetLastError(0);
484 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
487 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
488 MAX_REPLY_LEN, 0, 0, 0);
494 FTP_SetResponseError(nResCode);
498 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
499 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
501 INTERNET_ASYNC_RESULT iar;
503 iar.dwResult = (DWORD)bSuccess;
504 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
505 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
506 &iar, sizeof(INTERNET_ASYNC_RESULT));
513 /***********************************************************************
514 * FtpFindFirstFileA (WININET.@)
516 * Search the specified directory
519 * HINTERNET on success
523 HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
524 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
526 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
527 LPWININETAPPINFOA hIC = NULL;
529 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
531 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
535 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
536 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
538 WORKREQUEST workRequest;
540 workRequest.asyncall = FTPFINDFIRSTFILEA;
541 workRequest.HFTPSESSION = (DWORD)hConnect;
542 workRequest.LPSZSEARCHFILE = (DWORD)FTP_strdup(lpszSearchFile);
543 workRequest.LPFINDFILEDATA = (DWORD)lpFindFileData;
544 workRequest.DWFLAGS = dwFlags;
545 workRequest.DWCONTEXT= dwContext;
547 INTERNET_AsyncCall(&workRequest);
552 return FTP_FtpFindFirstFileA(hConnect, lpszSearchFile, lpFindFileData,
558 /***********************************************************************
559 * FtpFindFirstFileA (WININET.@)
561 * Search the specified directory
564 * HINTERNET on success
568 HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect,
569 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
576 /***********************************************************************
577 * FTP_FtpFindFirstFileA (Internal)
579 * Search the specified directory
582 * HINTERNET on success
586 HINTERNET WINAPI FTP_FtpFindFirstFileA(HINTERNET hConnect,
587 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
590 LPWININETAPPINFOA hIC = NULL;
591 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect;
592 LPWININETFINDNEXTA hFindNext = NULL;
596 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
598 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
602 /* Clear any error information */
603 INTERNET_SetLastError(0);
605 if (!FTP_InitListenSocket(lpwfs))
608 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
611 if (!FTP_SendPortOrPasv(lpwfs))
614 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
615 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, lpszSearchFile,
616 hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
619 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
620 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
623 if (nResCode == 125 || nResCode == 150)
627 /* Get data socket to server */
628 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
630 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpFindFileData, dwContext);
632 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
633 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
634 if (nResCode != 226 && nResCode != 250)
635 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
641 FTP_SetResponseError(nResCode);
645 if (lpwfs->lstnSocket != -1)
646 close(lpwfs->lstnSocket);
648 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
650 INTERNET_ASYNC_RESULT iar;
654 iar.dwResult = (DWORD)hFindNext;
655 iar.dwError = ERROR_SUCCESS;
656 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
657 &iar, sizeof(INTERNET_ASYNC_RESULT));
660 iar.dwResult = (DWORD)hFindNext;
661 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
662 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
663 &iar, sizeof(INTERNET_ASYNC_RESULT));
666 return (HINTERNET)hFindNext;
670 /***********************************************************************
671 * FtpGetCurrentDirectoryA (WININET.@)
673 * Retrieves the current directory
680 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
681 LPDWORD lpdwCurrentDirectory)
683 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
684 LPWININETAPPINFOA hIC = NULL;
686 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
688 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
690 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
694 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
695 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
697 WORKREQUEST workRequest;
699 workRequest.asyncall = FTPGETCURRENTDIRECTORYA;
700 workRequest.HFTPSESSION = (DWORD)hFtpSession;
701 workRequest.LPSZDIRECTORY = (DWORD)lpszCurrentDirectory;
702 workRequest.LPDWDIRECTORY = (DWORD)lpdwCurrentDirectory;
704 return INTERNET_AsyncCall(&workRequest);
708 return FTP_FtpGetCurrentDirectoryA(hFtpSession, lpszCurrentDirectory,
709 lpdwCurrentDirectory);
714 /***********************************************************************
715 * FtpGetCurrentDirectoryW (WININET.@)
717 * Retrieves the current directory
724 BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory,
725 LPDWORD lpdwCurrentDirectory)
732 /***********************************************************************
733 * FTP_FtpGetCurrentDirectoryA (Internal)
735 * Retrieves the current directory
742 BOOL WINAPI FTP_FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
743 LPDWORD lpdwCurrentDirectory)
746 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
747 LPWININETAPPINFOA hIC = NULL;
748 DWORD bSuccess = FALSE;
750 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
752 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
754 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
758 /* Clear any error information */
759 INTERNET_SetLastError(0);
761 ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
763 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
764 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
765 hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext))
768 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
769 MAX_REPLY_LEN, hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext);
772 if (nResCode == 257) /* Extract directory name */
774 INT firstpos, lastpos, len;
775 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
777 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
779 if ('"' == lpszResponseBuffer[lastpos])
788 len = lastpos - firstpos - 1;
789 strncpy(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1],
790 len < *lpdwCurrentDirectory ? len : *lpdwCurrentDirectory);
791 *lpdwCurrentDirectory = len;
795 FTP_SetResponseError(nResCode);
799 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
801 INTERNET_ASYNC_RESULT iar;
803 iar.dwResult = (DWORD)bSuccess;
804 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
805 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
806 &iar, sizeof(INTERNET_ASYNC_RESULT));
809 return (DWORD) bSuccess;
812 /***********************************************************************
813 * FtpOpenFileA (WININET.@)
815 * Open a remote file for writing or reading
818 * HINTERNET handle on success
822 HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
823 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
826 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
827 LPWININETAPPINFOA hIC = NULL;
829 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
831 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
835 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
836 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
838 WORKREQUEST workRequest;
840 workRequest.asyncall = FTPOPENFILEA;
841 workRequest.HFTPSESSION = (DWORD)hFtpSession;
842 workRequest.LPSZFILENAME = (DWORD)FTP_strdup(lpszFileName);
843 workRequest.FDWACCESS = fdwAccess;
844 workRequest.DWFLAGS = dwFlags;
845 workRequest.DWCONTEXT = dwContext;
847 INTERNET_AsyncCall(&workRequest);
852 return FTP_FtpOpenFileA(hFtpSession, lpszFileName, fdwAccess, dwFlags, dwContext);
857 /***********************************************************************
858 * FtpOpenFileW (WININET.@)
860 * Open a remote file for writing or reading
863 * HINTERNET handle on success
867 HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession,
868 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
876 /***********************************************************************
877 * FTP_FtpOpenFileA (Internal)
879 * Open a remote file for writing or reading
882 * HINTERNET handle on success
886 HINTERNET FTP_FtpOpenFileA(HINTERNET hFtpSession,
887 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
891 BOOL bSuccess = FALSE;
892 LPWININETFILE hFile = NULL;
893 LPWININETAPPINFOA hIC = NULL;
894 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
898 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
900 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
904 /* Clear any error information */
905 INTERNET_SetLastError(0);
907 if (GENERIC_READ == fdwAccess)
909 /* Set up socket to retrieve data */
910 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
912 else if (GENERIC_WRITE == fdwAccess)
914 /* Set up socket to send data */
915 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
918 /* Get data socket to server */
919 if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
921 hFile = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFILE));
922 hFile->hdr.htype = WH_HFILE;
923 hFile->hdr.dwFlags = dwFlags;
924 hFile->hdr.dwContext = dwContext;
925 hFile->hdr.lpwhparent = hFtpSession;
926 hFile->nDataSocket = nDataSocket;
929 if (lpwfs->lstnSocket != -1)
930 close(lpwfs->lstnSocket);
932 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
933 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
935 INTERNET_ASYNC_RESULT iar;
939 iar.dwResult = (DWORD)hFile;
940 iar.dwError = ERROR_SUCCESS;
941 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
942 &iar, sizeof(INTERNET_ASYNC_RESULT));
945 iar.dwResult = (DWORD)bSuccess;
946 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
947 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
948 &iar, sizeof(INTERNET_ASYNC_RESULT));
951 return (HINTERNET)hFile;
955 /***********************************************************************
956 * FtpGetFileA (WININET.@)
958 * Retrieve file from the FTP server
965 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
966 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
969 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hInternet;
970 LPWININETAPPINFOA hIC = NULL;
972 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
974 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
978 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
979 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
981 WORKREQUEST workRequest;
983 workRequest.asyncall = FTPGETFILEA;
984 workRequest.HFTPSESSION = (DWORD)hInternet;
985 workRequest.LPSZREMOTEFILE = (DWORD)FTP_strdup(lpszRemoteFile);
986 workRequest.LPSZNEWFILE = (DWORD)FTP_strdup(lpszNewFile);
987 workRequest.DWLOCALFLAGSATTRIBUTE = dwLocalFlagsAttribute;
988 workRequest.FFAILIFEXISTS = (DWORD)fFailIfExists;
989 workRequest.DWFLAGS = dwInternetFlags;
990 workRequest.DWCONTEXT = dwContext;
992 return INTERNET_AsyncCall(&workRequest);
996 return FTP_FtpGetFileA(hInternet, lpszRemoteFile, lpszNewFile,
997 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1002 /***********************************************************************
1003 * FtpGetFileW (WININET.@)
1005 * Retrieve file from the FTP server
1012 BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1013 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1021 /***********************************************************************
1022 * FTP_FtpGetFileA (Internal)
1024 * Retrieve file from the FTP server
1031 BOOL WINAPI FTP_FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1032 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1036 BOOL bSuccess = FALSE;
1038 LPWININETAPPINFOA hIC = NULL;
1039 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hInternet;
1041 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", lpszRemoteFile, lpszNewFile);
1042 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1044 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1048 /* Clear any error information */
1049 INTERNET_SetLastError(0);
1051 /* Ensure we can write to lpszNewfile by opening it */
1052 hFile = CreateFileA(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
1053 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
1054 if (INVALID_HANDLE_VALUE == hFile)
1057 /* Set up socket to retrieve data */
1058 nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags);
1064 /* Get data socket to server */
1065 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
1070 FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile);
1071 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1072 MAX_REPLY_LEN, 0, 0, 0);
1075 if (nResCode == 226)
1078 FTP_SetResponseError(nResCode);
1085 if (lpwfs->lstnSocket != -1)
1086 close(lpwfs->lstnSocket);
1091 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1092 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1094 INTERNET_ASYNC_RESULT iar;
1096 iar.dwResult = (DWORD)bSuccess;
1097 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1098 hIC->lpfnStatusCB(hInternet, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1099 &iar, sizeof(INTERNET_ASYNC_RESULT));
1106 /***********************************************************************
1107 * FtpDeleteFileA (WININET.@)
1109 * Delete a file on the ftp server
1116 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1118 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1119 LPWININETAPPINFOA hIC = NULL;
1121 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1123 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1127 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1128 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1130 WORKREQUEST workRequest;
1132 workRequest.asyncall = FTPRENAMEFILEA;
1133 workRequest.HFTPSESSION = (DWORD)hFtpSession;
1134 workRequest.LPSZFILENAME = (DWORD)FTP_strdup(lpszFileName);
1136 return INTERNET_AsyncCall(&workRequest);
1140 return FTP_FtpDeleteFileA(hFtpSession, lpszFileName);
1145 /***********************************************************************
1146 * FTP_FtpDeleteFileA (Internal)
1148 * Delete a file on the ftp server
1155 BOOL FTP_FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1158 BOOL bSuccess = FALSE;
1159 LPWININETAPPINFOA hIC = NULL;
1160 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1162 TRACE("0x%08lx\n", (ULONG) hFtpSession);
1163 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1165 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1169 /* Clear any error information */
1170 INTERNET_SetLastError(0);
1172 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1175 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1176 MAX_REPLY_LEN, 0, 0, 0);
1179 if (nResCode == 250)
1182 FTP_SetResponseError(nResCode);
1185 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1186 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1188 INTERNET_ASYNC_RESULT iar;
1190 iar.dwResult = (DWORD)bSuccess;
1191 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1192 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1193 &iar, sizeof(INTERNET_ASYNC_RESULT));
1200 /***********************************************************************
1201 * FtpRemoveDirectoryA (WININET.@)
1203 * Remove a directory on the ftp server
1210 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1212 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1213 LPWININETAPPINFOA hIC = NULL;
1215 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1217 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1221 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1222 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1224 WORKREQUEST workRequest;
1226 workRequest.asyncall = FTPREMOVEDIRECTORYA;
1227 workRequest.HFTPSESSION = (DWORD)hFtpSession;
1228 workRequest.LPSZDIRECTORY = (DWORD)FTP_strdup(lpszDirectory);
1230 return INTERNET_AsyncCall(&workRequest);
1234 return FTP_FtpRemoveDirectoryA(hFtpSession, lpszDirectory);
1239 /***********************************************************************
1240 * FTP_FtpRemoveDirectoryA (Internal)
1242 * Remove a directory on the ftp server
1249 BOOL FTP_FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1252 BOOL bSuccess = FALSE;
1253 LPWININETAPPINFOA hIC = NULL;
1254 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1257 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1259 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1263 /* Clear any error information */
1264 INTERNET_SetLastError(0);
1266 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1269 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1270 MAX_REPLY_LEN, 0, 0, 0);
1273 if (nResCode == 250)
1276 FTP_SetResponseError(nResCode);
1280 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1281 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1283 INTERNET_ASYNC_RESULT iar;
1285 iar.dwResult = (DWORD)bSuccess;
1286 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1287 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1288 &iar, sizeof(INTERNET_ASYNC_RESULT));
1295 /***********************************************************************
1296 * FtpRenameFileA (WININET.@)
1298 * Rename a file on the ftp server
1305 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1307 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1308 LPWININETAPPINFOA hIC = NULL;
1310 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1312 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1316 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1317 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1319 WORKREQUEST workRequest;
1321 workRequest.asyncall = FTPRENAMEFILEA;
1322 workRequest.HFTPSESSION = (DWORD)hFtpSession;
1323 workRequest.LPSZSRCFILE = (DWORD)FTP_strdup(lpszSrc);
1324 workRequest.LPSZDESTFILE = (DWORD)FTP_strdup(lpszDest);
1326 return INTERNET_AsyncCall(&workRequest);
1330 return FTP_FtpRenameFileA(hFtpSession, lpszSrc, lpszDest);
1334 /***********************************************************************
1335 * FTP_FtpRenameFileA (Internal)
1337 * Rename a file on the ftp server
1344 BOOL FTP_FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1347 BOOL bSuccess = FALSE;
1348 LPWININETAPPINFOA hIC = NULL;
1349 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession;
1352 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1354 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1358 /* Clear any error information */
1359 INTERNET_SetLastError(0);
1361 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1364 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket,
1365 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1366 if (nResCode == 350)
1368 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1371 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket,
1372 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1375 if (nResCode == 250)
1378 FTP_SetResponseError(nResCode);
1381 hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent;
1382 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1384 INTERNET_ASYNC_RESULT iar;
1386 iar.dwResult = (DWORD)bSuccess;
1387 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1388 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1389 &iar, sizeof(INTERNET_ASYNC_RESULT));
1396 /***********************************************************************
1397 * FTP_Connect (internal)
1399 * Connect to a ftp server
1402 * HINTERNET a session handle on success
1407 HINTERNET FTP_Connect(HINTERNET hInternet, LPCSTR lpszServerName,
1408 INTERNET_PORT nServerPort, LPCSTR lpszUserName,
1409 LPCSTR lpszPassword, DWORD dwFlags, DWORD dwContext)
1411 struct sockaddr_in socketAddr;
1412 struct hostent *phe = NULL;
1413 INT nsocket = -1, sock_namelen;
1414 LPWININETAPPINFOA hIC = NULL;
1415 BOOL bSuccess = FALSE;
1416 LPWININETFTPSESSIONA lpwfs = NULL;
1418 TRACE("0x%08lx Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1419 (ULONG) hInternet, lpszServerName,
1420 nServerPort, lpszUserName, lpszPassword);
1422 if (((LPWININETHANDLEHEADER)hInternet)->htype != WH_HINIT)
1425 hIC = (LPWININETAPPINFOA) hInternet;
1427 if (NULL == lpszUserName && NULL != lpszPassword)
1429 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_USER_NAME);
1433 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1434 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1436 if (hIC->lpfnStatusCB)
1437 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1438 (LPSTR) lpszServerName, strlen(lpszServerName));
1440 if (!GetAddress(lpszServerName, nServerPort, &phe, &socketAddr))
1442 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1446 if (hIC->lpfnStatusCB)
1447 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1448 (LPSTR) lpszServerName, strlen(lpszServerName));
1450 nsocket = socket(AF_INET,SOCK_STREAM,0);
1453 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1457 if (hIC->lpfnStatusCB)
1458 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1459 &socketAddr, sizeof(struct sockaddr_in));
1461 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1463 ERR("Unable to connect (%s)\n", strerror(errno));
1464 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1468 TRACE("Connected to server\n");
1469 if (hIC->lpfnStatusCB)
1470 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1471 &socketAddr, sizeof(struct sockaddr_in));
1473 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONA));
1476 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1480 lpwfs->hdr.htype = WH_HFTPSESSION;
1481 lpwfs->hdr.dwFlags = dwFlags;
1482 lpwfs->hdr.dwContext = dwContext;
1483 lpwfs->hdr.lpwhparent = (LPWININETHANDLEHEADER)hInternet;
1484 lpwfs->sndSocket = nsocket;
1485 sock_namelen = sizeof(lpwfs->socketAddress);
1486 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
1487 lpwfs->phostent = phe;
1489 if (NULL == lpszUserName)
1491 lpwfs->lpszUserName = FTP_strdup("anonymous");
1492 lpwfs->lpszPassword = FTP_strdup("user@server");
1496 lpwfs->lpszUserName = FTP_strdup(lpszUserName);
1497 lpwfs->lpszPassword = FTP_strdup(lpszPassword);
1500 if (FTP_ConnectToHost(lpwfs))
1502 if (hIC->lpfnStatusCB)
1504 INTERNET_ASYNC_RESULT iar;
1506 iar.dwResult = (DWORD)lpwfs;
1507 iar.dwError = ERROR_SUCCESS;
1509 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_HANDLE_CREATED,
1510 &iar, sizeof(INTERNET_ASYNC_RESULT));
1512 TRACE("Successfully logged into server\n");
1518 if (!bSuccess && nsocket == -1)
1521 if (!bSuccess && lpwfs)
1523 HeapFree(GetProcessHeap(), 0, lpwfs);
1527 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1529 INTERNET_ASYNC_RESULT iar;
1531 iar.dwResult = (DWORD)lpwfs;
1532 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1533 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1534 &iar, sizeof(INTERNET_ASYNC_RESULT));
1537 return (HINTERNET) lpwfs;
1541 /***********************************************************************
1542 * FTP_ConnectToHost (internal)
1544 * Connect to a ftp server
1551 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs)
1554 BOOL bSuccess = FALSE;
1557 FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1559 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
1562 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1563 MAX_REPLY_LEN, 0, 0, 0);
1566 /* Login successful... */
1567 if (nResCode == 230)
1569 /* User name okay, need password... */
1570 else if (nResCode == 331)
1571 bSuccess = FTP_SendPassword(lpwfs);
1572 /* Need account for login... */
1573 else if (nResCode == 332)
1574 bSuccess = FTP_SendAccount(lpwfs);
1576 FTP_SetResponseError(nResCode);
1579 TRACE("Returning %d\n", bSuccess);
1585 /***********************************************************************
1586 * FTP_SendCommand (internal)
1588 * Send command to server
1595 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
1596 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1600 DWORD nBytesSent = 0;
1604 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
1607 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1609 bParamHasLen = lpszParam && strlen(lpszParam) > 0;
1610 len = (bParamHasLen ? strlen(lpszParam) : -1) + strlen(szFtpCommands[ftpCmd]) +
1612 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
1614 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1617 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], bParamHasLen ? " " : "",
1618 bParamHasLen ? lpszParam : "", szCRLF);
1620 TRACE("Sending (%s) len(%ld)\n", buf, len);
1621 while((nBytesSent < len) && (nRC != -1))
1623 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
1627 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
1630 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_REQUEST_SENT,
1631 &nBytesSent, sizeof(DWORD));
1633 TRACE("Sent %ld bytes\n", nBytesSent);
1638 /***********************************************************************
1639 * FTP_ReceiveResponse (internal)
1641 * Receive response from server
1644 * Reply code on success
1649 INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse,
1650 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1654 char firstprefix[5];
1655 BOOL multiline = FALSE;
1658 TRACE("socket(%d) \n", nSocket);
1661 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1666 if (!INTERNET_GetNextLine(nSocket, lpszResponse, &nRecv))
1673 if(lpszResponse[3] != '-')
1676 { /* Start of multiline repsonse. Loop until we get "nnn " */
1678 memcpy(firstprefix, lpszResponse, 3);
1679 firstprefix[3] = ' ';
1680 firstprefix[4] = '\0';
1685 if(!memcmp(firstprefix, lpszResponse, 4))
1693 lpszResponse[nRecv] = '\0';
1694 rc = atoi(lpszResponse);
1697 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
1698 &nRecv, sizeof(DWORD));
1702 TRACE("return %d\n", rc);
1707 /***********************************************************************
1708 * FTP_SendPassword (internal)
1710 * Send password to ftp server
1717 BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs)
1720 BOOL bSuccess = FALSE;
1723 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
1726 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1727 MAX_REPLY_LEN, 0, 0, 0);
1730 TRACE("Received reply code %d\n", nResCode);
1731 /* Login successful... */
1732 if (nResCode == 230)
1734 /* Command not implemented, superfluous at the server site... */
1735 /* Need account for login... */
1736 else if (nResCode == 332)
1737 bSuccess = FTP_SendAccount(lpwfs);
1739 FTP_SetResponseError(nResCode);
1743 TRACE("Returning %d\n", bSuccess);
1748 /***********************************************************************
1749 * FTP_SendAccount (internal)
1758 BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs)
1761 BOOL bSuccess = FALSE;
1764 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, NOACCOUNT, 0, 0, 0))
1767 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1768 MAX_REPLY_LEN, 0, 0, 0);
1772 FTP_SetResponseError(nResCode);
1779 /***********************************************************************
1780 * FTP_SendStore (internal)
1782 * Send request to upload file to ftp server
1789 BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
1792 BOOL bSuccess = FALSE;
1795 if (!FTP_InitListenSocket(lpwfs))
1798 if (!FTP_SendType(lpwfs, dwType))
1801 if (!FTP_SendPortOrPasv(lpwfs))
1804 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
1806 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1807 MAX_REPLY_LEN, 0, 0, 0);
1810 if (nResCode == 150)
1813 FTP_SetResponseError(nResCode);
1817 if (!bSuccess && lpwfs->lstnSocket != -1)
1819 close(lpwfs->lstnSocket);
1820 lpwfs->lstnSocket = -1;
1827 /***********************************************************************
1828 * FTP_InitListenSocket (internal)
1830 * Create a socket to listen for server response
1837 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs)
1839 BOOL bSuccess = FALSE;
1840 size_t namelen = sizeof(struct sockaddr_in);
1844 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
1845 if (lpwfs->lstnSocket == -1)
1847 TRACE("Unable to create listening socket\n");
1851 /* We obtain our ip addr from the name of the command channel socket */
1852 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
1854 /* and get the system to assign us a port */
1855 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
1857 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
1859 TRACE("Unable to bind socket\n");
1863 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
1865 TRACE("listen failed\n");
1869 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
1873 if (!bSuccess && lpwfs->lstnSocket == -1)
1875 close(lpwfs->lstnSocket);
1876 lpwfs->lstnSocket = -1;
1883 /***********************************************************************
1884 * FTP_SendType (internal)
1886 * Tell server type of data being transferred
1892 * W98SE doesn't cache the type that's currently set
1893 * (i.e. it sends it always),
1894 * so we probably don't want to do that either.
1896 BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType)
1899 CHAR type[2] = { "I\0" };
1900 BOOL bSuccess = FALSE;
1903 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
1906 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
1909 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1910 MAX_REPLY_LEN, 0, 0, 0)/100;
1916 FTP_SetResponseError(nResCode);
1924 /***********************************************************************
1925 * FTP_SendPort (internal)
1927 * Tell server which port to use
1934 BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs)
1937 CHAR szIPAddress[64];
1938 BOOL bSuccess = FALSE;
1941 sprintf(szIPAddress, "%d,%d,%d,%d,%d,%d",
1942 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
1943 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
1944 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
1945 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
1946 lpwfs->lstnSocketAddress.sin_port & 0xFF,
1947 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
1949 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
1952 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1953 MAX_REPLY_LEN,0, 0, 0);
1956 if (nResCode == 200)
1959 FTP_SetResponseError(nResCode);
1967 /***********************************************************************
1968 * FTP_DoPassive (internal)
1970 * Tell server that we want to do passive transfers
1971 * and connect data socket
1978 BOOL FTP_DoPassive(LPWININETFTPSESSIONA lpwfs)
1981 BOOL bSuccess = FALSE;
1984 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
1987 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1988 MAX_REPLY_LEN,0, 0, 0);
1991 if (nResCode == 227)
1993 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
1997 char *pAddr, *pPort;
1999 struct sockaddr_in dataSocketAddress;
2001 p = lpszResponseBuffer+4; /* skip status code */
2003 /* do a very strict check; we can improve that later. */
2005 if (strncmp(p, "Entering Passive Mode", 21))
2007 ERR("unknown response '%.*s', aborting\n", 21, p);
2010 p += 21; /* skip string */
2011 if ((*p++ != ' ') || (*p++ != '('))
2013 ERR("unknown response format, aborting\n");
2017 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2020 ERR("unknown response address format '%s', aborting\n", p);
2023 for (i=0; i < 6; i++)
2026 dataSocketAddress = lpwfs->socketAddress;
2027 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2028 pPort = (char *)&(dataSocketAddress.sin_port);
2036 nsocket = socket(AF_INET,SOCK_STREAM,0);
2040 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2042 ERR("can't connect passive FTP data port.\n");
2045 lpwfs->pasvSocket = nsocket;
2049 FTP_SetResponseError(nResCode);
2057 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs)
2059 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2061 if (!FTP_DoPassive(lpwfs))
2066 if (!FTP_SendPort(lpwfs))
2073 /***********************************************************************
2074 * FTP_GetDataSocket (internal)
2076 * Either accepts an incoming data socket connection from the server
2077 * or just returns the already opened socket after a PASV command
2078 * in case of passive FTP.
2086 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket)
2088 struct sockaddr_in saddr;
2089 size_t addrlen = sizeof(struct sockaddr);
2092 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2094 *nDataSocket = lpwfs->pasvSocket;
2098 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2099 close(lpwfs->lstnSocket);
2100 lpwfs->lstnSocket = -1;
2102 return *nDataSocket != -1;
2106 /***********************************************************************
2107 * FTP_SendData (internal)
2109 * Send data to the server
2116 BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile)
2118 BY_HANDLE_FILE_INFORMATION fi;
2119 DWORD nBytesRead = 0;
2120 DWORD nBytesSent = 0;
2121 DWORD nTotalSent = 0;
2122 DWORD nBytesToSend, nLen, nRC = 1;
2123 time_t s_long_time, e_long_time;
2128 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2129 memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2131 /* Get the size of the file. */
2132 GetFileInformationByHandle(hFile, &fi);
2137 nBytesToSend = nBytesRead - nBytesSent;
2139 if (nBytesToSend <= 0)
2141 /* Read data from file. */
2143 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2144 ERR("Failed reading from file\n");
2147 nBytesToSend = nBytesRead;
2152 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2153 DATA_PACKET_SIZE : nBytesToSend;
2154 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2162 /* Do some computation to display the status. */
2164 nSeconds = e_long_time - s_long_time;
2165 if( nSeconds / 60 > 0 )
2167 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld min %ld sec estimated remainig time %ld sec\n",
2168 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2169 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2173 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld sec estimated remainig time %ld sec\n",
2174 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2175 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2177 } while (nRC != -1);
2179 TRACE("file transfer complete!\n");
2181 if(lpszBuffer != NULL)
2182 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2188 /***********************************************************************
2189 * FTP_SendRetrieve (internal)
2191 * Send request to retrieve a file
2194 * Number of bytes to be received on success
2198 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
2204 if (!FTP_InitListenSocket(lpwfs))
2207 if (!FTP_SendType(lpwfs, dwType))
2210 if (!FTP_SendPortOrPasv(lpwfs))
2213 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2216 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2217 MAX_REPLY_LEN, 0, 0, 0);
2220 if (nResCode == 125 || nResCode == 150)
2222 /* Parse size of data to be retrieved */
2223 INT i, sizepos = -1;
2224 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2225 for (i = strlen(lpszResponseBuffer) - 1; i >= 0; i--)
2227 if ('(' == lpszResponseBuffer[i])
2236 nResult = atol(&lpszResponseBuffer[sizepos+1]);
2237 TRACE("Waiting to receive %ld bytes\n", nResult);
2243 if (0 == nResult && lpwfs->lstnSocket != -1)
2245 close(lpwfs->lstnSocket);
2246 lpwfs->lstnSocket = -1;
2253 /***********************************************************************
2254 * FTP_RetrieveData (internal)
2256 * Retrieve data from server
2263 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2265 DWORD nBytesWritten;
2266 DWORD nBytesReceived = 0;
2272 if (INVALID_HANDLE_VALUE == hFile)
2275 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2276 if (NULL == lpszBuffer)
2278 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2282 while (nBytesReceived < nBytes && nRC != -1)
2284 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2287 /* other side closed socket. */
2290 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2291 nBytesReceived += nRC;
2294 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived, nBytes,
2295 nBytesReceived * 100 / nBytes);
2298 TRACE("Data transfer complete\n");
2299 if (NULL != lpszBuffer)
2300 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2307 /***********************************************************************
2308 * FTP_CloseSessionHandle (internal)
2310 * Deallocate session handle
2317 BOOL FTP_CloseSessionHandle(LPWININETFTPSESSIONA lpwfs)
2319 if (lpwfs->sndSocket != -1)
2320 close(lpwfs->sndSocket);
2322 if (lpwfs->lstnSocket != -1)
2323 close(lpwfs->lstnSocket);
2325 if (lpwfs->lpszPassword)
2326 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2328 if (lpwfs->lpszUserName)
2329 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2331 HeapFree(GetProcessHeap(), 0, lpwfs);
2337 /***********************************************************************
2338 * FTP_CloseSessionHandle (internal)
2340 * Deallocate session handle
2347 BOOL FTP_CloseFindNextHandle(LPWININETFINDNEXTA lpwfn)
2353 for (i = 0; i < lpwfn->size; i++)
2355 if (NULL != lpwfn->lpafp[i].lpszName)
2356 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2359 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2360 HeapFree(GetProcessHeap(), 0, lpwfn);
2366 /***********************************************************************
2367 * FTP_ReceiveFileList (internal)
2369 * Read file list from server
2372 * Handle to file list on success
2376 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket,
2377 LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext)
2380 LPFILEPROPERTIESA lpafp = NULL;
2381 LPWININETFINDNEXTA lpwfn = NULL;
2385 if (FTP_ParseDirectory(lpwfs, nSocket, &lpafp, &dwSize))
2387 FTP_ConvertFileProp(lpafp, lpFindFileData);
2389 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFINDNEXTA));
2392 lpwfn->hdr.htype = WH_HFINDNEXT;
2393 lpwfn->hdr.lpwhparent = (LPWININETHANDLEHEADER)lpwfs;
2394 lpwfn->hdr.dwContext = dwContext;
2395 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
2396 lpwfn->size = dwSize;
2397 lpwfn->lpafp = lpafp;
2401 TRACE("Matched %ld files\n", dwSize);
2402 return (HINTERNET)lpwfn;
2406 /***********************************************************************
2407 * FTP_ConvertFileProp (internal)
2409 * Converts FILEPROPERTIESA struct to WIN32_FIND_DATAA
2416 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESA lpafp, LPWIN32_FIND_DATAA lpFindFileData)
2418 BOOL bSuccess = FALSE;
2420 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
2424 DWORD access = mktime(&lpafp->tmLastModified);
2426 /* Not all fields are filled in */
2427 lpFindFileData->ftLastAccessTime.dwHighDateTime = HIWORD(access);
2428 lpFindFileData->ftLastAccessTime.dwLowDateTime = LOWORD(access);
2429 lpFindFileData->nFileSizeHigh = HIWORD(lpafp->nSize);
2430 lpFindFileData->nFileSizeLow = LOWORD(lpafp->nSize);
2432 if (lpafp->bIsDirectory)
2433 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
2435 if (lpafp->lpszName)
2436 strncpy(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
2445 /***********************************************************************
2446 * FTP_ParseDirectory (internal)
2448 * Parse string of directory information
2454 * FIXME: - This function needs serious clea-up
2455 * - We should consider both UNIX and NT list formats
2457 #define MAX_MONTH_LEN 10
2458 #define MIN_LEN_DIR_ENTRY 15
2460 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp)
2463 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2466 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2472 CHAR pszMonth[MAX_MONTH_LEN];
2474 BOOL bSuccess = TRUE;
2475 DWORD nBufLen = MAX_REPLY_LEN;
2476 LPFILEPROPERTIESA curFileProp = NULL;
2477 CHAR* pszLine = NULL;
2478 CHAR* pszToken = NULL;
2479 INT nTokenToSkip = 3;
2487 INT sizeFilePropArray = 20;
2488 INT indexFilePropArray = 0;
2492 /* Allocate intial file properties array */
2493 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESA)*(sizeFilePropArray));
2500 while ((pszLine = INTERNET_GetNextLine(nSocket, INTERNET_GetResponseBuffer(), &nBufLen)) != NULL)
2502 if (sizeFilePropArray <= indexFilePropArray)
2504 LPFILEPROPERTIESA tmpafp;
2506 sizeFilePropArray *= 2;
2507 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
2508 sizeof(FILEPROPERTIESA)*sizeFilePropArray);
2518 curFileProp = &((*lpafp)[indexFilePropArray]);
2520 /* First Parse the permissions. */
2521 pszToken = strtok(pszLine, " \t" );
2523 /* HACK! If this is not a file listing skip the line */
2524 if (!pszToken || 10 != strlen(pszToken) || nBufLen <= MIN_LEN_DIR_ENTRY)
2526 nBufLen = MAX_REPLY_LEN;
2530 FTP_ParsePermission(pszToken, curFileProp);
2536 pszToken = strtok( NULL, " \t" );
2538 } while( nCount <= nTokenToSkip );
2540 /* Store the size of the file in the param list. */
2541 TRACE("nSize-> %s\n", pszToken);
2542 if (pszToken != NULL)
2543 curFileProp->nSize = atol(pszToken);
2545 /* Parse last modified time. */
2553 pszToken = strtok( NULL, " \t" );
2554 strncpy(pszMonth, pszToken, MAX_MONTH_LEN);
2555 CharUpperA(pszMonth);
2556 pszMatch = strstr(szMonths, pszMonth);
2557 if( pszMatch != NULL )
2558 nMonth = (pszMatch - szMonths) / 3;
2560 pszToken = strtok(NULL, " \t");
2561 TRACE("nDay -> %s\n", pszToken);
2562 if (pszToken != NULL)
2563 nDay = atoi(pszToken);
2565 pszToken = strtok(NULL, " \t");
2566 pszMinutes = strchr(pszToken, ':');
2567 if( pszMinutes != NULL )
2570 nMinutes = atoi(pszMinutes);
2571 pszHour = pszMinutes - 3;
2572 if (pszHour != NULL)
2573 nHour = atoi(pszHour);
2575 apTM = localtime( &aTime );
2576 nYear = apTM->tm_year;
2580 nYear = atoi(pszToken);
2585 curFileProp->tmLastModified.tm_sec = nSeconds;
2586 curFileProp->tmLastModified.tm_min = nMinutes;
2587 curFileProp->tmLastModified.tm_hour = nHour;
2588 curFileProp->tmLastModified.tm_mday = nDay;
2589 curFileProp->tmLastModified.tm_mon = nMonth;
2590 curFileProp->tmLastModified.tm_year = nYear;
2592 pszToken = strtok(NULL, " \t");
2593 if(pszToken != NULL)
2595 curFileProp->lpszName = FTP_strdup(pszToken);
2596 TRACE(": %s\n", curFileProp->lpszName);
2599 nBufLen = MAX_REPLY_LEN;
2600 indexFilePropArray++;
2603 if (bSuccess && indexFilePropArray)
2605 if (indexFilePropArray < sizeFilePropArray - 1)
2607 LPFILEPROPERTIESA tmpafp;
2609 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
2610 sizeof(FILEPROPERTIESA)*indexFilePropArray);
2614 *dwfp = indexFilePropArray;
2618 HeapFree(GetProcessHeap(), 0, *lpafp);
2619 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2628 /***********************************************************************
2629 * FTP_ParsePermission (internal)
2631 * Parse permission string of directory information
2638 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp)
2640 BOOL bSuccess = TRUE;
2641 unsigned short nPermission = 0;
2646 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
2652 lpfp->bIsDirectory = (*lpszPermission == 'd');
2658 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
2661 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
2664 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
2667 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
2670 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
2673 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
2676 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
2679 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
2682 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
2686 }while (nPos <= nLast);
2688 lpfp->permissions = nPermission;
2693 /***********************************************************************
2694 * FTP_SetResponseError (internal)
2696 * Set the appropriate error code for a given response from the server
2701 DWORD FTP_SetResponseError(DWORD dwResponse)
2707 case 421: /* Service not available - Server may be shutting down. */
2708 dwCode = ERROR_INTERNET_TIMEOUT;
2711 case 425: /* Cannot open data connection. */
2712 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
2715 case 426: /* Connection closed, transer aborted. */
2716 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
2719 case 500: /* Syntax error. Command unrecognized. */
2720 case 501: /* Syntax error. Error in parameters or arguments. */
2721 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
2724 case 530: /* Not logged in. Login incorrect. */
2725 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
2728 case 550: /* File action not taken. File not found or no access. */
2729 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
2732 case 450: /* File action not taken. File may be busy. */
2733 case 451: /* Action aborted. Server error. */
2734 case 452: /* Action not taken. Insufficient storage space on server. */
2735 case 502: /* Command not implemented. */
2736 case 503: /* Bad sequence of command. */
2737 case 504: /* Command not implemented for that parameter. */
2738 case 532: /* Need account for storing files */
2739 case 551: /* Requested action aborted. Page type unknown */
2740 case 552: /* Action aborted. Exceeded storage allocation */
2741 case 553: /* Action not taken. File name not allowed. */
2744 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
2748 INTERNET_SetLastError(dwCode);