2 * WININET - Ftp implementation
4 * Copyright 1999 Corel Corporation
5 * Copyright 2004 Mike McCormack for CodeWeavers
10 * Copyright 2000 Andreas Mohr
11 * Copyright 2002 Jaco Greeff
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include "wine/port.h"
36 #include <sys/types.h>
37 #ifdef HAVE_SYS_SOCKET_H
38 # include <sys/socket.h>
55 #include "wine/debug.h"
58 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
60 #define NOACCOUNT "noaccount"
61 #define DATA_PACKET_SIZE 0x2000
66 /* FTP commands with arguments. */
82 /* FTP commands without arguments. */
91 static const CHAR *szFtpCommands[] = {
114 static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
116 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
117 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
118 BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType);
119 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket);
120 BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile);
121 INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse,
122 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext);
123 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType);
124 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile);
125 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs);
126 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs);
127 BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs);
128 BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs);
129 BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType);
130 BOOL FTP_GetFileSize(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD *dwSize);
131 BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs);
132 BOOL FTP_DoPassive(LPWININETFTPSESSIONA lpwfs);
133 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs);
134 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp);
135 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp);
136 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket,
137 LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext);
138 DWORD FTP_SetResponseError(DWORD dwResponse);
140 inline static LPSTR FTP_strdup( LPCSTR str )
142 LPSTR ret = HeapAlloc( GetProcessHeap(), 0, strlen(str) + 1 );
143 if (ret) strcpy( ret, str );
147 inline static LPSTR FTP_strdup_WtoA( LPCWSTR str )
149 int len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
150 LPSTR ret = HeapAlloc( GetProcessHeap(), 0, len );
152 WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL);
156 /***********************************************************************
157 * FtpPutFileA (WININET.@)
159 * Uploads a file to the FTP server
166 BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
167 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
169 LPWININETFTPSESSIONA lpwfs;
170 LPWININETAPPINFOW hIC = NULL;
172 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hConnect );
173 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
175 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
179 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
180 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
182 WORKREQUEST workRequest;
183 struct WORKREQ_FTPPUTFILEA *req = &workRequest.u.FtpPutFileA;
185 workRequest.asyncall = FTPPUTFILEA;
186 workRequest.handle = hConnect;
187 req->lpszLocalFile = FTP_strdup(lpszLocalFile);
188 req->lpszNewRemoteFile = FTP_strdup(lpszNewRemoteFile);
189 req->dwFlags = dwFlags;
190 req->dwContext = dwContext;
192 return INTERNET_AsyncCall(&workRequest);
196 return FTP_FtpPutFileA(hConnect, lpszLocalFile,
197 lpszNewRemoteFile, dwFlags, dwContext);
201 /***********************************************************************
202 * FTP_FtpPutFileA (Internal)
204 * Uploads a file to the FTP server
211 BOOL WINAPI FTP_FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
212 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
215 BOOL bSuccess = FALSE;
216 LPWININETAPPINFOW hIC = NULL;
217 LPWININETFTPSESSIONA lpwfs;
220 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", lpszLocalFile, lpszNewRemoteFile);
222 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hConnect );
223 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
225 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
229 /* Clear any error information */
230 INTERNET_SetLastError(0);
232 /* Open file to be uploaded */
233 if (INVALID_HANDLE_VALUE ==
234 (hFile = CreateFileA(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
236 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND);
240 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
241 if (hIC->lpfnStatusCB)
242 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
244 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
248 /* Get data socket to server */
249 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
251 FTP_SendData(lpwfs, nDataSocket, hFile);
253 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
254 MAX_REPLY_LEN, 0, 0, 0);
260 FTP_SetResponseError(nResCode);
266 if (lpwfs->lstnSocket != -1)
267 close(lpwfs->lstnSocket);
269 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
271 INTERNET_ASYNC_RESULT iar;
273 iar.dwResult = (DWORD)bSuccess;
274 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
275 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
276 &iar, sizeof(INTERNET_ASYNC_RESULT));
286 /***********************************************************************
287 * FtpSetCurrentDirectoryA (WININET.@)
289 * Change the working directory on the FTP server
296 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
298 LPWININETFTPSESSIONA lpwfs;
299 LPWININETAPPINFOW hIC = NULL;
301 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hConnect );
302 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
304 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
308 TRACE("lpszDirectory(%s)\n", lpszDirectory);
310 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
311 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
313 WORKREQUEST workRequest;
314 struct WORKREQ_FTPSETCURRENTDIRECTORYA *req;
316 workRequest.asyncall = FTPSETCURRENTDIRECTORYA;
317 workRequest.handle = hConnect;
318 req = &workRequest.u.FtpSetCurrentDirectoryA;
319 req->lpszDirectory = FTP_strdup(lpszDirectory);
321 return INTERNET_AsyncCall(&workRequest);
325 return FTP_FtpSetCurrentDirectoryA(hConnect, lpszDirectory);
330 /***********************************************************************
331 * FtpSetCurrentDirectoryW (WININET.@)
333 * Change the working directory on the FTP server
340 BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
346 len = WideCharToMultiByte(CP_ACP, 0, lpszDirectory, -1, NULL, 0, NULL, NULL);
347 szDir = HeapAlloc(GetProcessHeap(), 0, len);
350 WideCharToMultiByte(CP_ACP, 0, lpszDirectory, -1, szDir, len, NULL, NULL);
351 rc = FtpSetCurrentDirectoryA(hConnect, szDir);
352 HeapFree(GetProcessHeap(), 0, szDir);
358 /***********************************************************************
359 * FTP_FtpSetCurrentDirectoryA (Internal)
361 * Change the working directory on the FTP server
368 BOOL WINAPI FTP_FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
371 LPWININETFTPSESSIONA lpwfs;
372 LPWININETAPPINFOW hIC = NULL;
373 DWORD bSuccess = FALSE;
375 TRACE("lpszDirectory(%s)\n", lpszDirectory);
377 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hConnect );
378 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
380 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
384 /* Clear any error information */
385 INTERNET_SetLastError(0);
387 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
388 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
389 hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
392 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
393 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
400 FTP_SetResponseError(nResCode);
404 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
406 INTERNET_ASYNC_RESULT iar;
408 iar.dwResult = (DWORD)bSuccess;
409 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
410 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
411 &iar, sizeof(INTERNET_ASYNC_RESULT));
417 /***********************************************************************
418 * FtpCreateDirectoryA (WININET.@)
420 * Create new directory on the FTP server
427 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
429 LPWININETFTPSESSIONA lpwfs;
430 LPWININETAPPINFOW hIC = NULL;
432 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hConnect );
433 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
435 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
439 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
440 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
442 WORKREQUEST workRequest;
443 struct WORKREQ_FTPCREATEDIRECTORYA *req;
445 workRequest.asyncall = FTPCREATEDIRECTORYA;
446 workRequest.handle = hConnect;
447 req = &workRequest.u.FtpCreateDirectoryA;
448 req->lpszDirectory = FTP_strdup(lpszDirectory);
450 return INTERNET_AsyncCall(&workRequest);
454 return FTP_FtpCreateDirectoryA(hConnect, lpszDirectory);
459 /***********************************************************************
460 * FtpCreateDirectoryW (WININET.@)
462 * Create new directory on the FTP server
469 BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
475 len = WideCharToMultiByte(CP_ACP, 0, lpszDirectory, -1, NULL, 0, NULL, NULL);
476 szDir = HeapAlloc(GetProcessHeap(), 0, len);
479 WideCharToMultiByte(CP_ACP, 0, lpszDirectory, -1, szDir, len, NULL, NULL);
480 rc = FtpCreateDirectoryA(hConnect, szDir);
481 HeapFree(GetProcessHeap(), 0, szDir);
487 /***********************************************************************
488 * FTP_FtpCreateDirectoryA (Internal)
490 * Create new directory on the FTP server
497 BOOL WINAPI FTP_FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
500 BOOL bSuccess = FALSE;
501 LPWININETAPPINFOW hIC = NULL;
502 LPWININETFTPSESSIONA lpwfs;
506 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hConnect );
507 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
509 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
513 /* Clear any error information */
514 INTERNET_SetLastError(0);
516 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
519 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
520 MAX_REPLY_LEN, 0, 0, 0);
526 FTP_SetResponseError(nResCode);
530 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
531 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
533 INTERNET_ASYNC_RESULT iar;
535 iar.dwResult = (DWORD)bSuccess;
536 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
537 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
538 &iar, sizeof(INTERNET_ASYNC_RESULT));
545 /***********************************************************************
546 * FtpFindFirstFileA (WININET.@)
548 * Search the specified directory
551 * HINTERNET on success
555 HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
556 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
558 LPWININETFTPSESSIONA lpwfs;
559 LPWININETAPPINFOW hIC = NULL;
561 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hConnect );
562 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
564 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
568 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
569 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
571 WORKREQUEST workRequest;
572 struct WORKREQ_FTPFINDFIRSTFILEA *req;
574 workRequest.asyncall = FTPFINDFIRSTFILEA;
575 workRequest.handle = hConnect;
576 req = &workRequest.u.FtpFindFirstFileA;
577 req->lpszSearchFile = FTP_strdup(lpszSearchFile);
578 req->lpFindFileData = lpFindFileData;
579 req->dwFlags = dwFlags;
580 req->dwContext= dwContext;
582 INTERNET_AsyncCall(&workRequest);
587 return FTP_FtpFindFirstFileA(hConnect, lpszSearchFile, lpFindFileData,
593 /***********************************************************************
594 * FtpFindFirstFileA (WININET.@)
596 * Search the specified directory
599 * HINTERNET on success
603 HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect,
604 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
611 /***********************************************************************
612 * FTP_FtpFindFirstFileA (Internal)
614 * Search the specified directory
617 * HINTERNET on success
621 HINTERNET WINAPI FTP_FtpFindFirstFileA(HINTERNET hConnect,
622 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
625 LPWININETAPPINFOW hIC = NULL;
626 LPWININETFTPSESSIONA lpwfs;
627 HINTERNET hFindNext = NULL;
631 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hConnect );
632 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
634 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
638 /* Clear any error information */
639 INTERNET_SetLastError(0);
641 if (!FTP_InitListenSocket(lpwfs))
644 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
647 if (!FTP_SendPortOrPasv(lpwfs))
650 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
651 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, lpszSearchFile,
652 hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext))
655 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
656 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
659 if (nResCode == 125 || nResCode == 150)
663 /* Get data socket to server */
664 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
666 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpFindFileData, dwContext);
668 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
669 MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext);
670 if (nResCode != 226 && nResCode != 250)
671 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
677 FTP_SetResponseError(nResCode);
681 if (lpwfs->lstnSocket != -1)
682 close(lpwfs->lstnSocket);
684 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
686 INTERNET_ASYNC_RESULT iar;
690 iar.dwResult = (DWORD)hFindNext;
691 iar.dwError = ERROR_SUCCESS;
692 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
693 &iar, sizeof(INTERNET_ASYNC_RESULT));
696 iar.dwResult = (DWORD)hFindNext;
697 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
698 hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
699 &iar, sizeof(INTERNET_ASYNC_RESULT));
706 /***********************************************************************
707 * FtpGetCurrentDirectoryA (WININET.@)
709 * Retrieves the current directory
716 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
717 LPDWORD lpdwCurrentDirectory)
719 LPWININETFTPSESSIONA lpwfs;
720 LPWININETAPPINFOW hIC = NULL;
722 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
724 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hFtpSession );
725 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
727 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
731 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
732 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
734 WORKREQUEST workRequest;
735 struct WORKREQ_FTPGETCURRENTDIRECTORYA *req;
737 workRequest.asyncall = FTPGETCURRENTDIRECTORYA;
738 workRequest.handle = hFtpSession;
739 req = &workRequest.u.FtpGetCurrentDirectoryA;
740 req->lpszDirectory = lpszCurrentDirectory;
741 req->lpdwDirectory = lpdwCurrentDirectory;
743 return INTERNET_AsyncCall(&workRequest);
747 return FTP_FtpGetCurrentDirectoryA(hFtpSession, lpszCurrentDirectory,
748 lpdwCurrentDirectory);
753 /***********************************************************************
754 * FtpGetCurrentDirectoryW (WININET.@)
756 * Retrieves the current directory
763 BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory,
764 LPDWORD lpdwCurrentDirectory)
771 /***********************************************************************
772 * FTP_FtpGetCurrentDirectoryA (Internal)
774 * Retrieves the current directory
781 BOOL WINAPI FTP_FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
782 LPDWORD lpdwCurrentDirectory)
785 LPWININETFTPSESSIONA lpwfs;
786 LPWININETAPPINFOW hIC = NULL;
787 DWORD bSuccess = FALSE;
789 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
791 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hFtpSession );
792 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
794 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
798 /* Clear any error information */
799 INTERNET_SetLastError(0);
801 ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
803 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
804 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
805 hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext))
808 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
809 MAX_REPLY_LEN, hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext);
812 if (nResCode == 257) /* Extract directory name */
814 INT firstpos, lastpos, len;
815 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
817 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
819 if ('"' == lpszResponseBuffer[lastpos])
828 len = lastpos - firstpos - 1;
829 strncpy(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1],
830 len < *lpdwCurrentDirectory ? len : *lpdwCurrentDirectory);
831 *lpdwCurrentDirectory = len;
835 FTP_SetResponseError(nResCode);
839 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
841 INTERNET_ASYNC_RESULT iar;
843 iar.dwResult = (DWORD)bSuccess;
844 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
845 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
846 &iar, sizeof(INTERNET_ASYNC_RESULT));
849 return (DWORD) bSuccess;
852 /***********************************************************************
853 * FtpOpenFileA (WININET.@)
855 * Open a remote file for writing or reading
858 * HINTERNET handle on success
862 HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
863 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
866 LPWININETFTPSESSIONA lpwfs;
867 LPWININETAPPINFOW hIC = NULL;
869 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hFtpSession );
870 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
872 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
876 if (lpwfs->download_in_progress != NULL) {
877 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
881 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
882 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
884 WORKREQUEST workRequest;
885 struct WORKREQ_FTPOPENFILEA *req;
887 workRequest.asyncall = FTPOPENFILEA;
888 workRequest.handle = hFtpSession;
889 req = &workRequest.u.FtpOpenFileA;
890 req->lpszFilename = FTP_strdup(lpszFileName);
891 req->dwAccess = fdwAccess;
892 req->dwFlags = dwFlags;
893 req->dwContext = dwContext;
895 INTERNET_AsyncCall(&workRequest);
900 return FTP_FtpOpenFileA(hFtpSession, lpszFileName, fdwAccess, dwFlags, dwContext);
905 /***********************************************************************
906 * FtpOpenFileW (WININET.@)
908 * Open a remote file for writing or reading
911 * HINTERNET handle on success
915 HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession,
916 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
924 /***********************************************************************
925 * FTP_FtpOpenFileA (Internal)
927 * Open a remote file for writing or reading
930 * HINTERNET handle on success
934 HINTERNET FTP_FtpOpenFileA(HINTERNET hFtpSession,
935 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
939 BOOL bSuccess = FALSE;
940 LPWININETFILE lpwh = NULL;
941 LPWININETAPPINFOW hIC = NULL;
942 LPWININETFTPSESSIONA lpwfs;
943 HINTERNET handle = NULL;
947 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hFtpSession );
948 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
950 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
954 /* Clear any error information */
955 INTERNET_SetLastError(0);
957 if (GENERIC_READ == fdwAccess)
959 /* Set up socket to retrieve data */
960 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
962 else if (GENERIC_WRITE == fdwAccess)
964 /* Set up socket to send data */
965 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
968 /* Get data socket to server */
969 if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
971 lpwh = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFILE));
972 handle = WININET_AllocHandle( &lpwh->hdr );
973 lpwh->hdr.htype = WH_HFILE;
974 lpwh->hdr.dwFlags = dwFlags;
975 lpwh->hdr.dwContext = dwContext;
976 lpwh->hdr.lpwhparent = &lpwfs->hdr;
977 lpwh->nDataSocket = nDataSocket;
978 lpwh->session_deleted = FALSE;
980 /* Indicate that a download is currently in progress */
981 lpwfs->download_in_progress = lpwh;
984 if (lpwfs->lstnSocket != -1)
985 close(lpwfs->lstnSocket);
987 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
988 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
990 INTERNET_ASYNC_RESULT iar;
994 iar.dwResult = (DWORD)handle;
995 iar.dwError = ERROR_SUCCESS;
996 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
997 &iar, sizeof(INTERNET_ASYNC_RESULT));
1000 iar.dwResult = (DWORD)bSuccess;
1001 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1002 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1003 &iar, sizeof(INTERNET_ASYNC_RESULT));
1010 /***********************************************************************
1011 * FtpGetFileA (WININET.@)
1013 * Retrieve file from the FTP server
1020 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1021 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1024 LPWININETFTPSESSIONA lpwfs;
1025 LPWININETAPPINFOW hIC = NULL;
1027 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hInternet );
1028 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1030 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1034 if (lpwfs->download_in_progress != NULL) {
1035 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1039 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1040 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1042 WORKREQUEST workRequest;
1043 struct WORKREQ_FTPGETFILEA *req;
1045 workRequest.asyncall = FTPGETFILEA;
1046 workRequest.handle = hInternet;
1047 req = &workRequest.u.FtpGetFileA;
1048 req->lpszRemoteFile = FTP_strdup(lpszRemoteFile);
1049 req->lpszNewFile = FTP_strdup(lpszNewFile);
1050 req->dwLocalFlagsAttribute = dwLocalFlagsAttribute;
1051 req->fFailIfExists = fFailIfExists;
1052 req->dwFlags = dwInternetFlags;
1053 req->dwContext = dwContext;
1055 return INTERNET_AsyncCall(&workRequest);
1059 return FTP_FtpGetFileA(hInternet, lpszRemoteFile, lpszNewFile,
1060 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1065 /***********************************************************************
1066 * FtpGetFileW (WININET.@)
1068 * Retrieve file from the FTP server
1075 BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1076 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1084 /***********************************************************************
1085 * FTP_FtpGetFileA (Internal)
1087 * Retrieve file from the FTP server
1094 BOOL WINAPI FTP_FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1095 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1099 BOOL bSuccess = FALSE;
1101 LPWININETAPPINFOW hIC = NULL;
1102 LPWININETFTPSESSIONA lpwfs;
1104 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", lpszRemoteFile, lpszNewFile);
1106 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hInternet );
1107 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1109 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1113 /* Clear any error information */
1114 INTERNET_SetLastError(0);
1116 /* Ensure we can write to lpszNewfile by opening it */
1117 hFile = CreateFileA(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
1118 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
1119 if (INVALID_HANDLE_VALUE == hFile)
1122 /* Set up socket to retrieve data */
1123 nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags);
1129 /* Get data socket to server */
1130 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
1135 FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile);
1136 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1137 MAX_REPLY_LEN, 0, 0, 0);
1140 if (nResCode == 226)
1143 FTP_SetResponseError(nResCode);
1150 if (lpwfs->lstnSocket != -1)
1151 close(lpwfs->lstnSocket);
1156 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1157 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1159 INTERNET_ASYNC_RESULT iar;
1161 iar.dwResult = (DWORD)bSuccess;
1162 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1163 hIC->lpfnStatusCB(hInternet, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1164 &iar, sizeof(INTERNET_ASYNC_RESULT));
1171 /***********************************************************************
1172 * FtpDeleteFileA (WININET.@)
1174 * Delete a file on the ftp server
1181 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1183 LPWININETFTPSESSIONA lpwfs;
1184 LPWININETAPPINFOW hIC = NULL;
1186 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hFtpSession );
1187 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1189 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1193 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1194 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1196 WORKREQUEST workRequest;
1197 struct WORKREQ_FTPDELETEFILEA *req;
1199 workRequest.asyncall = FTPDELETEFILEA;
1200 workRequest.handle = hFtpSession;
1201 req = &workRequest.u.FtpDeleteFileA;
1202 req->lpszFilename = FTP_strdup(lpszFileName);
1204 return INTERNET_AsyncCall(&workRequest);
1208 return FTP_FtpDeleteFileA(hFtpSession, lpszFileName);
1213 /***********************************************************************
1214 * FTP_FtpDeleteFileA (Internal)
1216 * Delete a file on the ftp server
1223 BOOL FTP_FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1226 BOOL bSuccess = FALSE;
1227 LPWININETAPPINFOW hIC = NULL;
1228 LPWININETFTPSESSIONA lpwfs;
1230 TRACE("0x%08lx\n", (ULONG) hFtpSession);
1232 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hFtpSession );
1233 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1235 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1239 /* Clear any error information */
1240 INTERNET_SetLastError(0);
1242 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1245 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1246 MAX_REPLY_LEN, 0, 0, 0);
1249 if (nResCode == 250)
1252 FTP_SetResponseError(nResCode);
1255 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1256 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1258 INTERNET_ASYNC_RESULT iar;
1260 iar.dwResult = (DWORD)bSuccess;
1261 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1262 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1263 &iar, sizeof(INTERNET_ASYNC_RESULT));
1270 /***********************************************************************
1271 * FtpRemoveDirectoryA (WININET.@)
1273 * Remove a directory on the ftp server
1280 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1282 LPWININETFTPSESSIONA lpwfs;
1283 LPWININETAPPINFOW hIC = NULL;
1285 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hFtpSession );
1286 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1288 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1292 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1293 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1295 WORKREQUEST workRequest;
1296 struct WORKREQ_FTPREMOVEDIRECTORYA *req;
1298 workRequest.asyncall = FTPREMOVEDIRECTORYA;
1299 workRequest.handle = hFtpSession;
1300 req = &workRequest.u.FtpRemoveDirectoryA;
1301 req->lpszDirectory = FTP_strdup(lpszDirectory);
1303 return INTERNET_AsyncCall(&workRequest);
1307 return FTP_FtpRemoveDirectoryA(hFtpSession, lpszDirectory);
1312 /***********************************************************************
1313 * FTP_FtpRemoveDirectoryA (Internal)
1315 * Remove a directory on the ftp server
1322 BOOL FTP_FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1325 BOOL bSuccess = FALSE;
1326 LPWININETAPPINFOW hIC = NULL;
1327 LPWININETFTPSESSIONA lpwfs;
1331 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hFtpSession );
1332 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1334 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1338 /* Clear any error information */
1339 INTERNET_SetLastError(0);
1341 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1344 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1345 MAX_REPLY_LEN, 0, 0, 0);
1348 if (nResCode == 250)
1351 FTP_SetResponseError(nResCode);
1355 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1356 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1358 INTERNET_ASYNC_RESULT iar;
1360 iar.dwResult = (DWORD)bSuccess;
1361 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1362 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1363 &iar, sizeof(INTERNET_ASYNC_RESULT));
1370 /***********************************************************************
1371 * FtpRenameFileA (WININET.@)
1373 * Rename a file on the ftp server
1380 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1382 LPWININETFTPSESSIONA lpwfs;
1383 LPWININETAPPINFOW hIC = NULL;
1385 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hFtpSession );
1386 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1388 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1392 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1393 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1395 WORKREQUEST workRequest;
1396 struct WORKREQ_FTPRENAMEFILEA *req;
1398 workRequest.asyncall = FTPRENAMEFILEA;
1399 workRequest.handle = hFtpSession;
1400 req = &workRequest.u.FtpRenameFileA;
1401 req->lpszSrcFile = FTP_strdup(lpszSrc);
1402 req->lpszDestFile = FTP_strdup(lpszDest);
1404 return INTERNET_AsyncCall(&workRequest);
1408 return FTP_FtpRenameFileA(hFtpSession, lpszSrc, lpszDest);
1412 /***********************************************************************
1413 * FTP_FtpRenameFileA (Internal)
1415 * Rename a file on the ftp server
1422 BOOL FTP_FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1425 BOOL bSuccess = FALSE;
1426 LPWININETAPPINFOW hIC = NULL;
1427 LPWININETFTPSESSIONA lpwfs;
1431 lpwfs = (LPWININETFTPSESSIONA) WININET_GetObject( hFtpSession );
1432 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1434 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1438 /* Clear any error information */
1439 INTERNET_SetLastError(0);
1441 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1444 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket,
1445 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1446 if (nResCode == 350)
1448 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1451 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket,
1452 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1455 if (nResCode == 250)
1458 FTP_SetResponseError(nResCode);
1461 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1462 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1464 INTERNET_ASYNC_RESULT iar;
1466 iar.dwResult = (DWORD)bSuccess;
1467 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1468 hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1469 &iar, sizeof(INTERNET_ASYNC_RESULT));
1476 /***********************************************************************
1477 * FTP_Connect (internal)
1479 * Connect to a ftp server
1482 * HINTERNET a session handle on success
1487 HINTERNET FTP_Connect(HINTERNET hInternet, LPCWSTR lpszServerName,
1488 INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
1489 LPCWSTR lpszPassword, DWORD dwFlags, DWORD dwContext)
1491 struct sockaddr_in socketAddr;
1492 struct hostent *phe = NULL;
1493 INT nsocket = -1, sock_namelen;
1494 LPWININETAPPINFOW hIC = NULL;
1495 BOOL bSuccess = FALSE;
1496 LPWININETFTPSESSIONA lpwfs = NULL;
1497 HINTERNET handle = NULL;
1499 TRACE("0x%08lx Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1500 (ULONG) hInternet, debugstr_w(lpszServerName),
1501 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword));
1503 hIC = (LPWININETAPPINFOW) WININET_GetObject( hInternet );
1504 if ( (hIC == NULL) || (hIC->hdr.htype != WH_HINIT) )
1507 if (NULL == lpszUserName && NULL != lpszPassword)
1509 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_USER_NAME);
1513 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1514 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1516 if (hIC->lpfnStatusCB)
1517 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1518 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1520 if (!GetAddress(lpszServerName, nServerPort, &phe, &socketAddr))
1522 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1526 if (hIC->lpfnStatusCB)
1527 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1528 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1530 nsocket = socket(AF_INET,SOCK_STREAM,0);
1533 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1537 if (hIC->lpfnStatusCB)
1538 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1539 &socketAddr, sizeof(struct sockaddr_in));
1541 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1543 ERR("Unable to connect (%s)\n", strerror(errno));
1544 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1548 TRACE("Connected to server\n");
1549 if (hIC->lpfnStatusCB)
1550 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1551 &socketAddr, sizeof(struct sockaddr_in));
1553 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONA));
1556 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1560 handle = WININET_AllocHandle( &lpwfs->hdr );
1563 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1567 lpwfs->hdr.htype = WH_HFTPSESSION;
1568 lpwfs->hdr.dwFlags = dwFlags;
1569 lpwfs->hdr.dwContext = dwContext;
1570 lpwfs->hdr.lpwhparent = (LPWININETHANDLEHEADER)hInternet;
1571 lpwfs->sndSocket = nsocket;
1572 lpwfs->download_in_progress = NULL;
1573 sock_namelen = sizeof(lpwfs->socketAddress);
1574 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
1575 lpwfs->phostent = phe;
1577 if (NULL == lpszUserName)
1579 lpwfs->lpszUserName = FTP_strdup("anonymous");
1580 lpwfs->lpszPassword = FTP_strdup("user@server");
1584 lpwfs->lpszUserName = FTP_strdup_WtoA(lpszUserName);
1585 lpwfs->lpszPassword = FTP_strdup_WtoA(lpszPassword);
1588 if (FTP_ConnectToHost(lpwfs))
1590 if (hIC->lpfnStatusCB)
1592 INTERNET_ASYNC_RESULT iar;
1594 iar.dwResult = (DWORD)handle;
1595 iar.dwError = ERROR_SUCCESS;
1597 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_HANDLE_CREATED,
1598 &iar, sizeof(INTERNET_ASYNC_RESULT));
1600 TRACE("Successfully logged into server\n");
1606 if (!bSuccess && nsocket == -1)
1609 if (!bSuccess && lpwfs)
1611 HeapFree(GetProcessHeap(), 0, lpwfs);
1612 WININET_FreeHandle( handle );
1616 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1618 INTERNET_ASYNC_RESULT iar;
1620 iar.dwResult = (DWORD)lpwfs;
1621 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1622 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1623 &iar, sizeof(INTERNET_ASYNC_RESULT));
1630 /***********************************************************************
1631 * FTP_ConnectToHost (internal)
1633 * Connect to a ftp server
1640 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs)
1643 BOOL bSuccess = FALSE;
1646 FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0);
1648 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
1651 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1652 MAX_REPLY_LEN, 0, 0, 0);
1655 /* Login successful... */
1656 if (nResCode == 230)
1658 /* User name okay, need password... */
1659 else if (nResCode == 331)
1660 bSuccess = FTP_SendPassword(lpwfs);
1661 /* Need account for login... */
1662 else if (nResCode == 332)
1663 bSuccess = FTP_SendAccount(lpwfs);
1665 FTP_SetResponseError(nResCode);
1668 TRACE("Returning %d\n", bSuccess);
1674 /***********************************************************************
1675 * FTP_SendCommand (internal)
1677 * Send command to server
1684 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
1685 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1689 DWORD nBytesSent = 0;
1693 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
1696 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1698 bParamHasLen = lpszParam && strlen(lpszParam) > 0;
1699 len = (bParamHasLen ? strlen(lpszParam) : -1) + strlen(szFtpCommands[ftpCmd]) +
1701 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
1703 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1706 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], bParamHasLen ? " " : "",
1707 bParamHasLen ? lpszParam : "", szCRLF);
1709 TRACE("Sending (%s) len(%ld)\n", buf, len);
1710 while((nBytesSent < len) && (nRC != -1))
1712 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
1716 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
1719 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_REQUEST_SENT,
1720 &nBytesSent, sizeof(DWORD));
1722 TRACE("Sent %ld bytes\n", nBytesSent);
1727 /***********************************************************************
1728 * FTP_ReceiveResponse (internal)
1730 * Receive response from server
1733 * Reply code on success
1738 INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse,
1739 INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext)
1743 char firstprefix[5];
1744 BOOL multiline = FALSE;
1747 TRACE("socket(%d) \n", nSocket);
1750 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1755 if (!INTERNET_GetNextLine(nSocket, lpszResponse, &nRecv))
1762 if(lpszResponse[3] != '-')
1765 { /* Start of multiline repsonse. Loop until we get "nnn " */
1767 memcpy(firstprefix, lpszResponse, 3);
1768 firstprefix[3] = ' ';
1769 firstprefix[4] = '\0';
1774 if(!memcmp(firstprefix, lpszResponse, 4))
1782 rc = atoi(lpszResponse);
1785 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
1786 &nRecv, sizeof(DWORD));
1790 TRACE("return %d\n", rc);
1795 /***********************************************************************
1796 * FTP_SendPassword (internal)
1798 * Send password to ftp server
1805 BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs)
1808 BOOL bSuccess = FALSE;
1811 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
1814 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1815 MAX_REPLY_LEN, 0, 0, 0);
1818 TRACE("Received reply code %d\n", nResCode);
1819 /* Login successful... */
1820 if (nResCode == 230)
1822 /* Command not implemented, superfluous at the server site... */
1823 /* Need account for login... */
1824 else if (nResCode == 332)
1825 bSuccess = FTP_SendAccount(lpwfs);
1827 FTP_SetResponseError(nResCode);
1831 TRACE("Returning %d\n", bSuccess);
1836 /***********************************************************************
1837 * FTP_SendAccount (internal)
1846 BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs)
1849 BOOL bSuccess = FALSE;
1852 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, NOACCOUNT, 0, 0, 0))
1855 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1856 MAX_REPLY_LEN, 0, 0, 0);
1860 FTP_SetResponseError(nResCode);
1867 /***********************************************************************
1868 * FTP_SendStore (internal)
1870 * Send request to upload file to ftp server
1877 BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
1880 BOOL bSuccess = FALSE;
1883 if (!FTP_InitListenSocket(lpwfs))
1886 if (!FTP_SendType(lpwfs, dwType))
1889 if (!FTP_SendPortOrPasv(lpwfs))
1892 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
1894 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1895 MAX_REPLY_LEN, 0, 0, 0);
1898 if (nResCode == 150)
1901 FTP_SetResponseError(nResCode);
1905 if (!bSuccess && lpwfs->lstnSocket != -1)
1907 close(lpwfs->lstnSocket);
1908 lpwfs->lstnSocket = -1;
1915 /***********************************************************************
1916 * FTP_InitListenSocket (internal)
1918 * Create a socket to listen for server response
1925 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs)
1927 BOOL bSuccess = FALSE;
1928 size_t namelen = sizeof(struct sockaddr_in);
1932 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
1933 if (lpwfs->lstnSocket == -1)
1935 TRACE("Unable to create listening socket\n");
1939 /* We obtain our ip addr from the name of the command channel socket */
1940 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
1942 /* and get the system to assign us a port */
1943 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
1945 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
1947 TRACE("Unable to bind socket\n");
1951 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
1953 TRACE("listen failed\n");
1957 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
1961 if (!bSuccess && lpwfs->lstnSocket == -1)
1963 close(lpwfs->lstnSocket);
1964 lpwfs->lstnSocket = -1;
1971 /***********************************************************************
1972 * FTP_SendType (internal)
1974 * Tell server type of data being transferred
1980 * W98SE doesn't cache the type that's currently set
1981 * (i.e. it sends it always),
1982 * so we probably don't want to do that either.
1984 BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType)
1987 CHAR type[2] = { "I" };
1988 BOOL bSuccess = FALSE;
1991 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
1994 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
1997 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
1998 MAX_REPLY_LEN, 0, 0, 0)/100;
2004 FTP_SetResponseError(nResCode);
2011 /***********************************************************************
2012 * FTP_GetFileSize (internal)
2014 * Retrieves from the server the size of the given file
2021 BOOL FTP_GetFileSize(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD *dwSize)
2024 BOOL bSuccess = FALSE;
2028 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
2031 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2032 MAX_REPLY_LEN, 0, 0, 0);
2035 if (nResCode == 213) {
2036 /* Now parses the output to get the actual file size */
2038 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2040 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
2041 if (lpszResponseBuffer[i] == '\0') return FALSE;
2042 *dwSize = atol(&(lpszResponseBuffer[i + 1]));
2046 FTP_SetResponseError(nResCode);
2055 /***********************************************************************
2056 * FTP_SendPort (internal)
2058 * Tell server which port to use
2065 BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs)
2068 CHAR szIPAddress[64];
2069 BOOL bSuccess = FALSE;
2072 sprintf(szIPAddress, "%d,%d,%d,%d,%d,%d",
2073 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2074 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2075 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2076 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2077 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2078 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2080 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2083 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2084 MAX_REPLY_LEN,0, 0, 0);
2087 if (nResCode == 200)
2090 FTP_SetResponseError(nResCode);
2098 /***********************************************************************
2099 * FTP_DoPassive (internal)
2101 * Tell server that we want to do passive transfers
2102 * and connect data socket
2109 BOOL FTP_DoPassive(LPWININETFTPSESSIONA lpwfs)
2112 BOOL bSuccess = FALSE;
2115 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2118 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2119 MAX_REPLY_LEN,0, 0, 0);
2122 if (nResCode == 227)
2124 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2128 char *pAddr, *pPort;
2130 struct sockaddr_in dataSocketAddress;
2132 p = lpszResponseBuffer+4; /* skip status code */
2134 /* do a very strict check; we can improve that later. */
2136 if (strncmp(p, "Entering Passive Mode", 21))
2138 ERR("unknown response '%.*s', aborting\n", 21, p);
2141 p += 21; /* skip string */
2142 if ((*p++ != ' ') || (*p++ != '('))
2144 ERR("unknown response format, aborting\n");
2148 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2151 ERR("unknown response address format '%s', aborting\n", p);
2154 for (i=0; i < 6; i++)
2157 dataSocketAddress = lpwfs->socketAddress;
2158 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2159 pPort = (char *)&(dataSocketAddress.sin_port);
2167 nsocket = socket(AF_INET,SOCK_STREAM,0);
2171 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2173 ERR("can't connect passive FTP data port.\n");
2176 lpwfs->pasvSocket = nsocket;
2180 FTP_SetResponseError(nResCode);
2188 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs)
2190 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2192 if (!FTP_DoPassive(lpwfs))
2197 if (!FTP_SendPort(lpwfs))
2204 /***********************************************************************
2205 * FTP_GetDataSocket (internal)
2207 * Either accepts an incoming data socket connection from the server
2208 * or just returns the already opened socket after a PASV command
2209 * in case of passive FTP.
2217 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket)
2219 struct sockaddr_in saddr;
2220 size_t addrlen = sizeof(struct sockaddr);
2223 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2225 *nDataSocket = lpwfs->pasvSocket;
2229 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2230 close(lpwfs->lstnSocket);
2231 lpwfs->lstnSocket = -1;
2233 return *nDataSocket != -1;
2237 /***********************************************************************
2238 * FTP_SendData (internal)
2240 * Send data to the server
2247 BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile)
2249 BY_HANDLE_FILE_INFORMATION fi;
2250 DWORD nBytesRead = 0;
2251 DWORD nBytesSent = 0;
2252 DWORD nTotalSent = 0;
2253 DWORD nBytesToSend, nLen, nRC = 1;
2254 time_t s_long_time, e_long_time;
2259 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2260 memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2262 /* Get the size of the file. */
2263 GetFileInformationByHandle(hFile, &fi);
2268 nBytesToSend = nBytesRead - nBytesSent;
2270 if (nBytesToSend <= 0)
2272 /* Read data from file. */
2274 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2275 ERR("Failed reading from file\n");
2278 nBytesToSend = nBytesRead;
2283 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2284 DATA_PACKET_SIZE : nBytesToSend;
2285 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2293 /* Do some computation to display the status. */
2295 nSeconds = e_long_time - s_long_time;
2296 if( nSeconds / 60 > 0 )
2298 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld min %ld sec estimated remainig time %ld sec\n",
2299 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2300 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2304 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld sec estimated remainig time %ld sec\n",
2305 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2306 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2308 } while (nRC != -1);
2310 TRACE("file transfer complete!\n");
2312 if(lpszBuffer != NULL)
2313 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2319 /***********************************************************************
2320 * FTP_SendRetrieve (internal)
2322 * Send request to retrieve a file
2325 * Number of bytes to be received on success
2329 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType)
2335 if (!FTP_InitListenSocket(lpwfs))
2338 if (!FTP_SendType(lpwfs, dwType))
2341 if (!FTP_SendPortOrPasv(lpwfs))
2344 if (!FTP_GetFileSize(lpwfs, lpszRemoteFile, &nResult))
2347 TRACE("Waiting to receive %ld bytes\n", nResult);
2349 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2352 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2353 MAX_REPLY_LEN, 0, 0, 0);
2354 if ((nResCode != 125) && (nResCode != 150)) {
2355 /* That means that we got an error getting the file. */
2360 if (0 == nResult && lpwfs->lstnSocket != -1)
2362 close(lpwfs->lstnSocket);
2363 lpwfs->lstnSocket = -1;
2370 /***********************************************************************
2371 * FTP_RetrieveData (internal)
2373 * Retrieve data from server
2380 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2382 DWORD nBytesWritten;
2383 DWORD nBytesReceived = 0;
2389 if (INVALID_HANDLE_VALUE == hFile)
2392 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2393 if (NULL == lpszBuffer)
2395 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2399 while (nBytesReceived < nBytes && nRC != -1)
2401 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2404 /* other side closed socket. */
2407 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2408 nBytesReceived += nRC;
2411 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived, nBytes,
2412 nBytesReceived * 100 / nBytes);
2415 TRACE("Data transfer complete\n");
2416 if (NULL != lpszBuffer)
2417 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2424 /***********************************************************************
2425 * FTP_CloseSessionHandle (internal)
2427 * Deallocate session handle
2434 BOOL FTP_CloseSessionHandle(LPWININETFTPSESSIONA lpwfs)
2438 if (lpwfs->download_in_progress != NULL)
2439 lpwfs->download_in_progress->session_deleted = TRUE;
2441 if (lpwfs->sndSocket != -1)
2442 close(lpwfs->sndSocket);
2444 if (lpwfs->lstnSocket != -1)
2445 close(lpwfs->lstnSocket);
2447 if (lpwfs->lpszPassword)
2448 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2450 if (lpwfs->lpszUserName)
2451 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2453 HeapFree(GetProcessHeap(), 0, lpwfs);
2459 /***********************************************************************
2460 * FTP_CloseFindNextHandle (internal)
2462 * Deallocate session handle
2469 BOOL FTP_CloseFindNextHandle(LPWININETFINDNEXTA lpwfn)
2475 for (i = 0; i < lpwfn->size; i++)
2477 if (NULL != lpwfn->lpafp[i].lpszName)
2478 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2481 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2482 HeapFree(GetProcessHeap(), 0, lpwfn);
2487 /***********************************************************************
2488 * FTP_CloseFileTransferHandle (internal)
2490 * Closes the file transfer handle. This also 'cleans' the data queue of
2491 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2498 BOOL FTP_CloseFileTransferHandle(LPWININETFILE lpwh)
2500 LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) lpwh->hdr.lpwhparent;
2505 if (!lpwh->session_deleted)
2506 lpwfs->download_in_progress = NULL;
2508 /* This just serves to flush the control socket of any spurrious lines written
2509 to it (like '226 Transfer complete.').
2511 Wonder what to do if the server sends us an error code though...
2513 nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
2514 MAX_REPLY_LEN, 0, 0, 0);
2516 if (lpwh->nDataSocket != -1)
2517 close(lpwh->nDataSocket);
2519 HeapFree(GetProcessHeap(), 0, lpwh);
2524 /***********************************************************************
2525 * FTP_ReceiveFileList (internal)
2527 * Read file list from server
2530 * Handle to file list on success
2534 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket,
2535 LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext)
2538 LPFILEPROPERTIESA lpafp = NULL;
2539 LPWININETFINDNEXTA lpwfn = NULL;
2540 HINTERNET handle = 0;
2544 if (FTP_ParseDirectory(lpwfs, nSocket, &lpafp, &dwSize))
2546 FTP_ConvertFileProp(lpafp, lpFindFileData);
2548 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFINDNEXTA));
2551 handle = WININET_AllocHandle( &lpwfn->hdr );
2554 lpwfn->hdr.htype = WH_HFINDNEXT;
2555 lpwfn->hdr.lpwhparent = (LPWININETHANDLEHEADER)lpwfs;
2556 lpwfn->hdr.dwContext = dwContext;
2557 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
2558 lpwfn->size = dwSize;
2559 lpwfn->lpafp = lpafp;
2562 HeapFree( GetProcessHeap(), 0, lpwfn );
2566 TRACE("Matched %ld files\n", dwSize);
2571 /***********************************************************************
2572 * FTP_ConvertFileProp (internal)
2574 * Converts FILEPROPERTIESA struct to WIN32_FIND_DATAA
2581 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESA lpafp, LPWIN32_FIND_DATAA lpFindFileData)
2583 BOOL bSuccess = FALSE;
2585 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
2589 /* Convert 'Unix' time to Windows time */
2590 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
2591 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
2593 /* Not all fields are filled in */
2594 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
2595 lpFindFileData->nFileSizeLow = lpafp->nSize;
2597 if (lpafp->bIsDirectory)
2598 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
2600 if (lpafp->lpszName)
2601 strncpy(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
2610 /***********************************************************************
2611 * FTP_ParseDirectory (internal)
2613 * Parse string of directory information
2619 * FIXME: - This function needs serious clea-up
2620 * - We should consider both UNIX and NT list formats
2622 #define MAX_MONTH_LEN 10
2623 #define MIN_LEN_DIR_ENTRY 15
2625 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp)
2628 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2631 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2637 CHAR pszMonth[MAX_MONTH_LEN];
2639 BOOL bSuccess = TRUE;
2640 DWORD nBufLen = MAX_REPLY_LEN;
2641 LPFILEPROPERTIESA curFileProp = NULL;
2642 CHAR* pszLine = NULL;
2643 CHAR* pszToken = NULL;
2644 INT nTokenToSkip = 3;
2652 INT sizeFilePropArray = 20;
2653 INT indexFilePropArray = 0;
2657 /* Allocate intial file properties array */
2658 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESA)*(sizeFilePropArray));
2665 while ((pszLine = INTERNET_GetNextLine(nSocket, INTERNET_GetResponseBuffer(), &nBufLen)) != NULL)
2667 if (sizeFilePropArray <= indexFilePropArray)
2669 LPFILEPROPERTIESA tmpafp;
2671 sizeFilePropArray *= 2;
2672 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
2673 sizeof(FILEPROPERTIESA)*sizeFilePropArray);
2683 curFileProp = &((*lpafp)[indexFilePropArray]);
2685 /* First Parse the permissions. */
2686 pszToken = strtok(pszLine, " \t" );
2688 /* HACK! If this is not a file listing skip the line */
2689 if (!pszToken || nBufLen <= MIN_LEN_DIR_ENTRY)
2691 nBufLen = MAX_REPLY_LEN;
2694 if (10 == strlen(pszToken)) {
2695 /* Unix way of parsing ... */
2696 FTP_ParsePermission(pszToken, curFileProp);
2701 pszToken = strtok( NULL, " \t" );
2703 } while( nCount <= nTokenToSkip );
2705 /* Store the size of the file in the param list. */
2706 TRACE("nSize-> %s\n", pszToken);
2707 if (pszToken != NULL)
2708 curFileProp->nSize = atol(pszToken);
2710 /* Parse last modified time. */
2718 pszToken = strtok( NULL, " \t" );
2719 strncpy(pszMonth, pszToken, MAX_MONTH_LEN);
2720 CharUpperA(pszMonth);
2721 pszMatch = strstr(szMonths, pszMonth);
2722 if( pszMatch != NULL )
2723 nMonth = (pszMatch - szMonths) / 3;
2725 pszToken = strtok(NULL, " \t");
2726 TRACE("nDay -> %s\n", pszToken);
2727 if (pszToken != NULL)
2728 nDay = atoi(pszToken);
2730 pszToken = strtok(NULL, " \t");
2731 pszMinutes = strchr(pszToken, ':');
2732 if( pszMinutes != NULL ) {
2734 nMinutes = atoi(pszMinutes);
2735 pszHour = pszMinutes - 3;
2736 if (pszHour != NULL)
2737 nHour = atoi(pszHour);
2739 apTM = localtime( &aTime );
2740 nYear = apTM->tm_year;
2742 nYear = atoi(pszToken);
2747 curFileProp->tmLastModified.tm_sec = nSeconds;
2748 curFileProp->tmLastModified.tm_min = nMinutes;
2749 curFileProp->tmLastModified.tm_hour = nHour;
2750 curFileProp->tmLastModified.tm_mday = nDay;
2751 curFileProp->tmLastModified.tm_mon = nMonth;
2752 curFileProp->tmLastModified.tm_year = nYear;
2754 pszToken = strtok(NULL, " \t");
2755 if(pszToken != NULL) {
2756 curFileProp->lpszName = FTP_strdup(pszToken);
2757 TRACE(": %s\n", curFileProp->lpszName);
2760 nBufLen = MAX_REPLY_LEN;
2761 indexFilePropArray++;
2762 } else if (8 == strlen(pszToken)) {
2763 /* NT way of parsing ... :
2765 07-13-03 08:55PM <DIR> sakpatch
2766 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
2769 curFileProp->permissions = 0xFFFF; /* No idea, put full permission :-) */
2771 sscanf(pszToken, "%d-%d-%d",
2772 &curFileProp->tmLastModified.tm_mon,
2773 &curFileProp->tmLastModified.tm_mday,
2774 &curFileProp->tmLastModified.tm_year);
2776 /* Hacky and bad Y2K protection :-) */
2777 if (curFileProp->tmLastModified.tm_year < 70)
2778 curFileProp->tmLastModified.tm_year += 100;
2780 pszToken = strtok(NULL, " \t");
2781 if (pszToken == NULL) {
2782 nBufLen = MAX_REPLY_LEN;
2785 sscanf(pszToken, "%d:%d",
2786 &curFileProp->tmLastModified.tm_hour,
2787 &curFileProp->tmLastModified.tm_min);
2788 if ((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
2789 curFileProp->tmLastModified.tm_hour += 12;
2791 curFileProp->tmLastModified.tm_sec = 0;
2793 TRACE("Mod time: %2d:%2d:%2d %2d/%2d/%2d\n",
2794 curFileProp->tmLastModified.tm_hour, curFileProp->tmLastModified.tm_min, curFileProp->tmLastModified.tm_sec,
2795 (curFileProp->tmLastModified.tm_year >= 100) ? curFileProp->tmLastModified.tm_year - 100 : curFileProp->tmLastModified.tm_year,
2796 curFileProp->tmLastModified.tm_mon, curFileProp->tmLastModified.tm_mday);
2798 pszToken = strtok(NULL, " \t");
2799 if (pszToken == NULL) {
2800 nBufLen = MAX_REPLY_LEN;
2803 if (!strcasecmp(pszToken, "<DIR>")) {
2804 curFileProp->bIsDirectory = TRUE;
2805 TRACE("Is directory\n");
2807 curFileProp->bIsDirectory = FALSE;
2808 curFileProp->nSize = atol(pszToken);
2809 TRACE("nSize: %ld\n", curFileProp->nSize);
2812 pszToken = strtok(NULL, " \t");
2813 if (pszToken == NULL) {
2814 nBufLen = MAX_REPLY_LEN;
2817 curFileProp->lpszName = FTP_strdup(pszToken);
2818 TRACE("Name: %s\n", curFileProp->lpszName);
2820 nBufLen = MAX_REPLY_LEN;
2821 indexFilePropArray++;
2823 nBufLen = MAX_REPLY_LEN;
2827 if (bSuccess && indexFilePropArray)
2829 if (indexFilePropArray < sizeFilePropArray - 1)
2831 LPFILEPROPERTIESA tmpafp;
2833 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
2834 sizeof(FILEPROPERTIESA)*indexFilePropArray);
2838 *dwfp = indexFilePropArray;
2842 HeapFree(GetProcessHeap(), 0, *lpafp);
2843 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2852 /***********************************************************************
2853 * FTP_ParsePermission (internal)
2855 * Parse permission string of directory information
2862 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp)
2864 BOOL bSuccess = TRUE;
2865 unsigned short nPermission = 0;
2870 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
2876 lpfp->bIsDirectory = (*lpszPermission == 'd');
2882 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
2885 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
2888 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
2891 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
2894 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
2897 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
2900 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
2903 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
2906 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
2910 }while (nPos <= nLast);
2912 lpfp->permissions = nPermission;
2917 /***********************************************************************
2918 * FTP_SetResponseError (internal)
2920 * Set the appropriate error code for a given response from the server
2925 DWORD FTP_SetResponseError(DWORD dwResponse)
2931 case 421: /* Service not available - Server may be shutting down. */
2932 dwCode = ERROR_INTERNET_TIMEOUT;
2935 case 425: /* Cannot open data connection. */
2936 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
2939 case 426: /* Connection closed, transer aborted. */
2940 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
2943 case 500: /* Syntax error. Command unrecognized. */
2944 case 501: /* Syntax error. Error in parameters or arguments. */
2945 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
2948 case 530: /* Not logged in. Login incorrect. */
2949 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
2952 case 550: /* File action not taken. File not found or no access. */
2953 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
2956 case 450: /* File action not taken. File may be busy. */
2957 case 451: /* Action aborted. Server error. */
2958 case 452: /* Action not taken. Insufficient storage space on server. */
2959 case 502: /* Command not implemented. */
2960 case 503: /* Bad sequence of command. */
2961 case 504: /* Command not implemented for that parameter. */
2962 case 532: /* Need account for storing files */
2963 case 551: /* Requested action aborted. Page type unknown */
2964 case 552: /* Action aborted. Exceeded storage allocation */
2965 case 553: /* Action not taken. File name not allowed. */
2968 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
2972 INTERNET_SetLastError(dwCode);