| /* | |
| * WININET - Ftp implementation | |
| * | |
| * Copyright 1999 Corel Corporation | |
| * | |
| * Ulrich Czekalla | |
| * Noureddine Jemmali | |
| * | |
| * Copyright 2000 Andreas Mohr | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| */ | |
| #include "config.h" | |
| #include "wine/port.h" | |
| #include <errno.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <sys/types.h> | |
| #ifdef HAVE_SYS_SOCKET_H | |
| # include <sys/socket.h> | |
| #endif | |
| #ifdef HAVE_UNISTD_H | |
| # include <unistd.h> | |
| #endif | |
| #include <time.h> | |
| #include "winbase.h" | |
| #include "wingdi.h" | |
| #include "winuser.h" | |
| #include "wininet.h" | |
| #include "winerror.h" | |
| #include "wine/debug.h" | |
| #include "internet.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(wininet); | |
| #define NOACCOUNT "noaccount" | |
| #define DATA_PACKET_SIZE 0x2000 | |
| #define szCRLF "\r\n" | |
| #define MAX_BACKLOG 5 | |
| typedef enum { | |
| /* FTP commands with arguments. */ | |
| FTP_CMD_ACCT, | |
| FTP_CMD_CWD, | |
| FTP_CMD_DELE, | |
| FTP_CMD_MKD, | |
| FTP_CMD_PASS, | |
| FTP_CMD_PORT, | |
| FTP_CMD_RETR, | |
| FTP_CMD_RMD, | |
| FTP_CMD_RNFR, | |
| FTP_CMD_RNTO, | |
| FTP_CMD_STOR, | |
| FTP_CMD_TYPE, | |
| FTP_CMD_USER, | |
| /* FTP commands without arguments. */ | |
| FTP_CMD_ABOR, | |
| FTP_CMD_LIST, | |
| FTP_CMD_NLST, | |
| FTP_CMD_PASV, | |
| FTP_CMD_PWD, | |
| FTP_CMD_QUIT, | |
| } FTP_COMMAND; | |
| static const CHAR *szFtpCommands[] = { | |
| "ACCT", | |
| "CWD", | |
| "DELE", | |
| "MKD", | |
| "PASS", | |
| "PORT", | |
| "RETR", | |
| "RMD", | |
| "RNFR", | |
| "RNTO", | |
| "STOR", | |
| "TYPE", | |
| "USER", | |
| "ABOR", | |
| "LIST", | |
| "NLST", | |
| "PASV", | |
| "PWD", | |
| "QUIT", | |
| }; | |
| static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"; | |
| BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam, | |
| INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext); | |
| BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType); | |
| BOOL FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket); | |
| BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile); | |
| INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse, | |
| INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext); | |
| DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType); | |
| BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile); | |
| BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs); | |
| BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs); | |
| BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs); | |
| BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs); | |
| BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType); | |
| BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs); | |
| BOOL FTP_DoPassive(LPWININETFTPSESSIONA lpwfs); | |
| BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs); | |
| BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp); | |
| BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp); | |
| HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket, | |
| LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext); | |
| DWORD FTP_SetResponseError(DWORD dwResponse); | |
| inline static LPSTR FTP_strdup( LPCSTR str ) | |
| { | |
| LPSTR ret = HeapAlloc( GetProcessHeap(), 0, strlen(str) + 1 ); | |
| if (ret) strcpy( ret, str ); | |
| return ret; | |
| } | |
| /*********************************************************************** | |
| * FtpPutFileA (WININET.@) | |
| * | |
| * Uploads a file to the FTP server | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * FALSE on failure | |
| * | |
| */ | |
| BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile, | |
| LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext) | |
| { | |
| LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect; | |
| LPWININETAPPINFOA hIC = NULL; | |
| if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype) | |
| { | |
| INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); | |
| return FALSE; | |
| } | |
| hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent; | |
| if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) | |
| { | |
| WORKREQUEST workRequest; | |
| workRequest.asyncall = FTPPUTFILEA; | |
| workRequest.HFTPSESSION = (DWORD)hConnect; | |
| workRequest.LPSZLOCALFILE = (DWORD)FTP_strdup(lpszLocalFile); | |
| workRequest.LPSZNEWREMOTEFILE = (DWORD)FTP_strdup(lpszNewRemoteFile); | |
| workRequest.DWFLAGS = dwFlags; | |
| workRequest.DWCONTEXT = dwContext; | |
| return INTERNET_AsyncCall(&workRequest); | |
| } | |
| else | |
| { | |
| return FTP_FtpPutFileA(hConnect, lpszLocalFile, | |
| lpszNewRemoteFile, dwFlags, dwContext); | |
| } | |
| } | |
| /*********************************************************************** | |
| * FTP_FtpPutFileA (Internal) | |
| * | |
| * Uploads a file to the FTP server | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * FALSE on failure | |
| * | |
| */ | |
| BOOL WINAPI FTP_FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile, | |
| LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext) | |
| { | |
| HANDLE hFile = (HANDLE)NULL; | |
| BOOL bSuccess = FALSE; | |
| LPWININETAPPINFOA hIC = NULL; | |
| LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect; | |
| INT nResCode; | |
| TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", lpszLocalFile, lpszNewRemoteFile); | |
| if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype) | |
| { | |
| INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); | |
| return FALSE; | |
| } | |
| /* Clear any error information */ | |
| INTERNET_SetLastError(0); | |
| /* Open file to be uploaded */ | |
| if (INVALID_HANDLE_VALUE == | |
| (hFile = CreateFileA(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0))) | |
| { | |
| INTERNET_SetLastError(ERROR_FILE_NOT_FOUND); | |
| goto lend; | |
| } | |
| hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent; | |
| if (hIC->lpfnStatusCB) | |
| hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0); | |
| if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags)) | |
| { | |
| INT nDataSocket; | |
| /* Get data socket to server */ | |
| if (FTP_GetDataSocket(lpwfs, &nDataSocket)) | |
| { | |
| FTP_SendData(lpwfs, nDataSocket, hFile); | |
| close(nDataSocket); | |
| nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), | |
| MAX_REPLY_LEN, 0, 0, 0); | |
| if (nResCode) | |
| { | |
| if (nResCode == 226) | |
| bSuccess = TRUE; | |
| else | |
| FTP_SetResponseError(nResCode); | |
| } | |
| } | |
| } | |
| lend: | |
| if (lpwfs->lstnSocket != -1) | |
| close(lpwfs->lstnSocket); | |
| if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB) | |
| { | |
| INTERNET_ASYNC_RESULT iar; | |
| iar.dwResult = (DWORD)bSuccess; | |
| iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError(); | |
| hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, | |
| &iar, sizeof(INTERNET_ASYNC_RESULT)); | |
| } | |
| if (hFile) | |
| CloseHandle(hFile); | |
| return bSuccess; | |
| } | |
| /*********************************************************************** | |
| * FtpSetCurrentDirectoryA (WININET.@) | |
| * | |
| * Change the working directory on the FTP server | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * FALSE on failure | |
| * | |
| */ | |
| BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory) | |
| { | |
| LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect; | |
| LPWININETAPPINFOA hIC = NULL; | |
| if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype) | |
| { | |
| INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); | |
| return FALSE; | |
| } | |
| TRACE("lpszDirectory(%s)\n", lpszDirectory); | |
| hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent; | |
| if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) | |
| { | |
| WORKREQUEST workRequest; | |
| workRequest.asyncall = FTPSETCURRENTDIRECTORYA; | |
| workRequest.HFTPSESSION = (DWORD)hConnect; | |
| workRequest.LPSZDIRECTORY = (DWORD)FTP_strdup(lpszDirectory); | |
| return INTERNET_AsyncCall(&workRequest); | |
| } | |
| else | |
| { | |
| return FTP_FtpSetCurrentDirectoryA(hConnect, lpszDirectory); | |
| } | |
| } | |
| /*********************************************************************** | |
| * FTP_FtpSetCurrentDirectoryA (Internal) | |
| * | |
| * Change the working directory on the FTP server | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * FALSE on failure | |
| * | |
| */ | |
| BOOL WINAPI FTP_FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory) | |
| { | |
| INT nResCode; | |
| LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect; | |
| LPWININETAPPINFOA hIC = NULL; | |
| DWORD bSuccess = FALSE; | |
| TRACE("lpszDirectory(%s)\n", lpszDirectory); | |
| if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype) | |
| { | |
| INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); | |
| return FALSE; | |
| } | |
| /* Clear any error information */ | |
| INTERNET_SetLastError(0); | |
| hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent; | |
| if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory, | |
| hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext)) | |
| goto lend; | |
| nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), | |
| MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext); | |
| if (nResCode) | |
| { | |
| if (nResCode == 250) | |
| bSuccess = TRUE; | |
| else | |
| FTP_SetResponseError(nResCode); | |
| } | |
| lend: | |
| if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB) | |
| { | |
| INTERNET_ASYNC_RESULT iar; | |
| iar.dwResult = (DWORD)bSuccess; | |
| iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR; | |
| hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, | |
| &iar, sizeof(INTERNET_ASYNC_RESULT)); | |
| } | |
| return bSuccess; | |
| } | |
| /*********************************************************************** | |
| * FtpCreateDirectoryA (WININET.@) | |
| * | |
| * Create new directory on the FTP server | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * FALSE on failure | |
| * | |
| */ | |
| BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory) | |
| { | |
| LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect; | |
| LPWININETAPPINFOA hIC = NULL; | |
| if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype) | |
| { | |
| INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); | |
| return FALSE; | |
| } | |
| hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent; | |
| if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) | |
| { | |
| WORKREQUEST workRequest; | |
| workRequest.asyncall = FTPCREATEDIRECTORYA; | |
| workRequest.HFTPSESSION = (DWORD)hConnect; | |
| workRequest.LPSZDIRECTORY = (DWORD)FTP_strdup(lpszDirectory); | |
| return INTERNET_AsyncCall(&workRequest); | |
| } | |
| else | |
| { | |
| return FTP_FtpCreateDirectoryA(hConnect, lpszDirectory); | |
| } | |
| } | |
| /*********************************************************************** | |
| * FTP_FtpCreateDirectoryA (Internal) | |
| * | |
| * Create new directory on the FTP server | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * FALSE on failure | |
| * | |
| */ | |
| BOOL WINAPI FTP_FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory) | |
| { | |
| INT nResCode; | |
| BOOL bSuccess = FALSE; | |
| LPWININETAPPINFOA hIC = NULL; | |
| LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect; | |
| TRACE("\n"); | |
| if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype) | |
| { | |
| INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); | |
| return FALSE; | |
| } | |
| /* Clear any error information */ | |
| INTERNET_SetLastError(0); | |
| if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0)) | |
| goto lend; | |
| nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), | |
| MAX_REPLY_LEN, 0, 0, 0); | |
| if (nResCode) | |
| { | |
| if (nResCode == 257) | |
| bSuccess = TRUE; | |
| else | |
| FTP_SetResponseError(nResCode); | |
| } | |
| lend: | |
| hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent; | |
| if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB) | |
| { | |
| INTERNET_ASYNC_RESULT iar; | |
| iar.dwResult = (DWORD)bSuccess; | |
| iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError(); | |
| hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, | |
| &iar, sizeof(INTERNET_ASYNC_RESULT)); | |
| } | |
| return bSuccess; | |
| } | |
| /*********************************************************************** | |
| * FtpFindFirstFileA (WININET.@) | |
| * | |
| * Search the specified directory | |
| * | |
| * RETURNS | |
| * HINTERNET on success | |
| * NULL on failure | |
| * | |
| */ | |
| HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect, | |
| LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext) | |
| { | |
| LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect; | |
| LPWININETAPPINFOA hIC = NULL; | |
| if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype) | |
| { | |
| INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); | |
| return FALSE; | |
| } | |
| hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent; | |
| if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) | |
| { | |
| WORKREQUEST workRequest; | |
| workRequest.asyncall = FTPFINDFIRSTFILEA; | |
| workRequest.HFTPSESSION = (DWORD)hConnect; | |
| workRequest.LPSZSEARCHFILE = (DWORD)FTP_strdup(lpszSearchFile); | |
| workRequest.LPFINDFILEDATA = (DWORD)lpFindFileData; | |
| workRequest.DWFLAGS = dwFlags; | |
| workRequest.DWCONTEXT= dwContext; | |
| INTERNET_AsyncCall(&workRequest); | |
| return NULL; | |
| } | |
| else | |
| { | |
| return FTP_FtpFindFirstFileA(hConnect, lpszSearchFile, lpFindFileData, | |
| dwFlags, dwContext); | |
| } | |
| } | |
| /*********************************************************************** | |
| * FTP_FtpFindFirstFileA (Internal) | |
| * | |
| * Search the specified directory | |
| * | |
| * RETURNS | |
| * HINTERNET on success | |
| * NULL on failure | |
| * | |
| */ | |
| HINTERNET WINAPI FTP_FtpFindFirstFileA(HINTERNET hConnect, | |
| LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext) | |
| { | |
| INT nResCode; | |
| LPWININETAPPINFOA hIC = NULL; | |
| LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hConnect; | |
| LPWININETFINDNEXTA hFindNext = NULL; | |
| TRACE("\n"); | |
| if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype) | |
| { | |
| INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); | |
| return FALSE; | |
| } | |
| /* Clear any error information */ | |
| INTERNET_SetLastError(0); | |
| if (!FTP_InitListenSocket(lpwfs)) | |
| goto lend; | |
| if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII)) | |
| goto lend; | |
| if (!FTP_SendPortOrPasv(lpwfs)) | |
| goto lend; | |
| hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent; | |
| if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, lpszSearchFile, | |
| hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext)) | |
| goto lend; | |
| nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), | |
| MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext); | |
| if (nResCode) | |
| { | |
| if (nResCode == 125 || nResCode == 150) | |
| { | |
| INT nDataSocket; | |
| /* Get data socket to server */ | |
| if (FTP_GetDataSocket(lpwfs, &nDataSocket)) | |
| { | |
| hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpFindFileData, dwContext); | |
| nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), | |
| MAX_REPLY_LEN, hIC->lpfnStatusCB, hConnect, lpwfs->hdr.dwContext); | |
| if (nResCode != 226 && nResCode != 250) | |
| INTERNET_SetLastError(ERROR_NO_MORE_FILES); | |
| close(nDataSocket); | |
| } | |
| } | |
| else | |
| FTP_SetResponseError(nResCode); | |
| } | |
| lend: | |
| if (lpwfs->lstnSocket != -1) | |
| close(lpwfs->lstnSocket); | |
| if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB) | |
| { | |
| INTERNET_ASYNC_RESULT iar; | |
| if (hFindNext) | |
| { | |
| iar.dwResult = (DWORD)hFindNext; | |
| iar.dwError = ERROR_SUCCESS; | |
| hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED, | |
| &iar, sizeof(INTERNET_ASYNC_RESULT)); | |
| } | |
| iar.dwResult = (DWORD)hFindNext; | |
| iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError(); | |
| hIC->lpfnStatusCB(hConnect, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, | |
| &iar, sizeof(INTERNET_ASYNC_RESULT)); | |
| } | |
| return (HINTERNET)hFindNext; | |
| } | |
| /*********************************************************************** | |
| * FtpGetCurrentDirectoryA (WININET.@) | |
| * | |
| * Retrieves the current directory | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * FALSE on failure | |
| * | |
| */ | |
| BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory, | |
| LPDWORD lpdwCurrentDirectory) | |
| { | |
| LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession; | |
| LPWININETAPPINFOA hIC = NULL; | |
| TRACE("len(%ld)\n", *lpdwCurrentDirectory); | |
| if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype) | |
| { | |
| INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); | |
| return FALSE; | |
| } | |
| hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent; | |
| if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) | |
| { | |
| WORKREQUEST workRequest; | |
| workRequest.asyncall = FTPGETCURRENTDIRECTORYA; | |
| workRequest.HFTPSESSION = (DWORD)hFtpSession; | |
| workRequest.LPSZDIRECTORY = (DWORD)lpszCurrentDirectory; | |
| workRequest.LPDWDIRECTORY = (DWORD)lpdwCurrentDirectory; | |
| return INTERNET_AsyncCall(&workRequest); | |
| } | |
| else | |
| { | |
| return FTP_FtpGetCurrentDirectoryA(hFtpSession, lpszCurrentDirectory, | |
| lpdwCurrentDirectory); | |
| } | |
| } | |
| /*********************************************************************** | |
| * FTP_FtpGetCurrentDirectoryA (Internal) | |
| * | |
| * Retrieves the current directory | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * FALSE on failure | |
| * | |
| */ | |
| BOOL WINAPI FTP_FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory, | |
| LPDWORD lpdwCurrentDirectory) | |
| { | |
| INT nResCode; | |
| LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession; | |
| LPWININETAPPINFOA hIC = NULL; | |
| DWORD bSuccess = FALSE; | |
| TRACE("len(%ld)\n", *lpdwCurrentDirectory); | |
| if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype) | |
| { | |
| INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); | |
| return FALSE; | |
| } | |
| /* Clear any error information */ | |
| INTERNET_SetLastError(0); | |
| ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory); | |
| hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent; | |
| if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL, | |
| hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext)) | |
| goto lend; | |
| nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), | |
| MAX_REPLY_LEN, hIC->lpfnStatusCB, hFtpSession, lpwfs->hdr.dwContext); | |
| if (nResCode) | |
| { | |
| if (nResCode == 257) /* Extract directory name */ | |
| { | |
| INT firstpos, lastpos, len; | |
| LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer(); | |
| for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++) | |
| { | |
| if ('"' == lpszResponseBuffer[lastpos]) | |
| { | |
| if (!firstpos) | |
| firstpos = lastpos; | |
| else | |
| break; | |
| } | |
| } | |
| len = lastpos - firstpos - 1; | |
| strncpy(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1], | |
| len < *lpdwCurrentDirectory ? len : *lpdwCurrentDirectory); | |
| *lpdwCurrentDirectory = len; | |
| bSuccess = TRUE; | |
| } | |
| else | |
| FTP_SetResponseError(nResCode); | |
| } | |
| lend: | |
| if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB) | |
| { | |
| INTERNET_ASYNC_RESULT iar; | |
| iar.dwResult = (DWORD)bSuccess; | |
| iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR; | |
| hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, | |
| &iar, sizeof(INTERNET_ASYNC_RESULT)); | |
| } | |
| return (DWORD) bSuccess; | |
| } | |
| /*********************************************************************** | |
| * FtpOpenFileA (WININET.@) | |
| * | |
| * Open a remote file for writing or reading | |
| * | |
| * RETURNS | |
| * HINTERNET handle on success | |
| * NULL on failure | |
| * | |
| */ | |
| HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession, | |
| LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags, | |
| DWORD dwContext) | |
| { | |
| LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession; | |
| LPWININETAPPINFOA hIC = NULL; | |
| if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype) | |
| { | |
| INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); | |
| return FALSE; | |
| } | |
| hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent; | |
| if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) | |
| { | |
| WORKREQUEST workRequest; | |
| workRequest.asyncall = FTPOPENFILEA; | |
| workRequest.HFTPSESSION = (DWORD)hFtpSession; | |
| workRequest.LPSZFILENAME = (DWORD)FTP_strdup(lpszFileName); | |
| workRequest.FDWACCESS = fdwAccess; | |
| workRequest.DWFLAGS = dwFlags; | |
| workRequest.DWCONTEXT = dwContext; | |
| INTERNET_AsyncCall(&workRequest); | |
| return NULL; | |
| } | |
| else | |
| { | |
| return FTP_FtpOpenFileA(hFtpSession, lpszFileName, fdwAccess, dwFlags, dwContext); | |
| } | |
| } | |
| /*********************************************************************** | |
| * FTP_FtpOpenFileA (Internal) | |
| * | |
| * Open a remote file for writing or reading | |
| * | |
| * RETURNS | |
| * HINTERNET handle on success | |
| * NULL on failure | |
| * | |
| */ | |
| HINTERNET FTP_FtpOpenFileA(HINTERNET hFtpSession, | |
| LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags, | |
| DWORD dwContext) | |
| { | |
| INT nDataSocket; | |
| BOOL bSuccess = FALSE; | |
| LPWININETFILE hFile = NULL; | |
| LPWININETAPPINFOA hIC = NULL; | |
| LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession; | |
| TRACE("\n"); | |
| if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype) | |
| { | |
| INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); | |
| return FALSE; | |
| } | |
| /* Clear any error information */ | |
| INTERNET_SetLastError(0); | |
| if (GENERIC_READ == fdwAccess) | |
| { | |
| /* Set up socket to retrieve data */ | |
| bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags); | |
| } | |
| else if (GENERIC_WRITE == fdwAccess) | |
| { | |
| /* Set up socket to send data */ | |
| bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags); | |
| } | |
| /* Get data socket to server */ | |
| if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket)) | |
| { | |
| hFile = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFILE)); | |
| hFile->hdr.htype = WH_HFILE; | |
| hFile->hdr.dwFlags = dwFlags; | |
| hFile->hdr.dwContext = dwContext; | |
| hFile->hdr.lpwhparent = hFtpSession; | |
| hFile->nDataSocket = nDataSocket; | |
| } | |
| if (lpwfs->lstnSocket != -1) | |
| close(lpwfs->lstnSocket); | |
| hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent; | |
| if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB) | |
| { | |
| INTERNET_ASYNC_RESULT iar; | |
| if (hFile) | |
| { | |
| iar.dwResult = (DWORD)hFile; | |
| iar.dwError = ERROR_SUCCESS; | |
| hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED, | |
| &iar, sizeof(INTERNET_ASYNC_RESULT)); | |
| } | |
| iar.dwResult = (DWORD)bSuccess; | |
| iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError(); | |
| hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, | |
| &iar, sizeof(INTERNET_ASYNC_RESULT)); | |
| } | |
| return (HINTERNET)hFile; | |
| } | |
| /*********************************************************************** | |
| * FtpGetFileA (WININET.@) | |
| * | |
| * Retrieve file from the FTP server | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * FALSE on failure | |
| * | |
| */ | |
| BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile, | |
| BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags, | |
| DWORD dwContext) | |
| { | |
| LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hInternet; | |
| LPWININETAPPINFOA hIC = NULL; | |
| if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype) | |
| { | |
| INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); | |
| return FALSE; | |
| } | |
| hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent; | |
| if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) | |
| { | |
| WORKREQUEST workRequest; | |
| workRequest.asyncall = FTPGETFILEA; | |
| workRequest.HFTPSESSION = (DWORD)hInternet; | |
| workRequest.LPSZREMOTEFILE = (DWORD)FTP_strdup(lpszRemoteFile); | |
| workRequest.LPSZNEWFILE = (DWORD)FTP_strdup(lpszNewFile); | |
| workRequest.DWLOCALFLAGSATTRIBUTE = dwLocalFlagsAttribute; | |
| workRequest.FFAILIFEXISTS = (DWORD)fFailIfExists; | |
| workRequest.DWFLAGS = dwInternetFlags; | |
| workRequest.DWCONTEXT = dwContext; | |
| return INTERNET_AsyncCall(&workRequest); | |
| } | |
| else | |
| { | |
| return FTP_FtpGetFileA(hInternet, lpszRemoteFile, lpszNewFile, | |
| fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext); | |
| } | |
| } | |
| /*********************************************************************** | |
| * FTP_FtpGetFileA (Internal) | |
| * | |
| * Retrieve file from the FTP server | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * FALSE on failure | |
| * | |
| */ | |
| BOOL WINAPI FTP_FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile, | |
| BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags, | |
| DWORD dwContext) | |
| { | |
| DWORD nBytes; | |
| BOOL bSuccess = FALSE; | |
| HANDLE hFile; | |
| LPWININETAPPINFOA hIC = NULL; | |
| LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hInternet; | |
| TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", lpszRemoteFile, lpszNewFile); | |
| if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype) | |
| { | |
| INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); | |
| return FALSE; | |
| } | |
| /* Clear any error information */ | |
| INTERNET_SetLastError(0); | |
| /* Ensure we can write to lpszNewfile by opening it */ | |
| hFile = CreateFileA(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ? | |
| CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0); | |
| if (INVALID_HANDLE_VALUE == hFile) | |
| goto lend; | |
| /* Set up socket to retrieve data */ | |
| nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags); | |
| if (nBytes > 0) | |
| { | |
| INT nDataSocket; | |
| /* Get data socket to server */ | |
| if (FTP_GetDataSocket(lpwfs, &nDataSocket)) | |
| { | |
| INT nResCode; | |
| /* Receive data */ | |
| FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile); | |
| nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), | |
| MAX_REPLY_LEN, 0, 0, 0); | |
| if (nResCode) | |
| { | |
| if (nResCode == 226) | |
| bSuccess = TRUE; | |
| else | |
| FTP_SetResponseError(nResCode); | |
| } | |
| close(nDataSocket); | |
| } | |
| } | |
| lend: | |
| if (lpwfs->lstnSocket != -1) | |
| close(lpwfs->lstnSocket); | |
| if (hFile) | |
| CloseHandle(hFile); | |
| hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent; | |
| if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB) | |
| { | |
| INTERNET_ASYNC_RESULT iar; | |
| iar.dwResult = (DWORD)bSuccess; | |
| iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError(); | |
| hIC->lpfnStatusCB(hInternet, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, | |
| &iar, sizeof(INTERNET_ASYNC_RESULT)); | |
| } | |
| return bSuccess; | |
| } | |
| /*********************************************************************** | |
| * FtpDeleteFileA (WININET.@) | |
| * | |
| * Delete a file on the ftp server | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * FALSE on failure | |
| * | |
| */ | |
| BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName) | |
| { | |
| LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession; | |
| LPWININETAPPINFOA hIC = NULL; | |
| if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype) | |
| { | |
| INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); | |
| return FALSE; | |
| } | |
| hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent; | |
| if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) | |
| { | |
| WORKREQUEST workRequest; | |
| workRequest.asyncall = FTPRENAMEFILEA; | |
| workRequest.HFTPSESSION = (DWORD)hFtpSession; | |
| workRequest.LPSZFILENAME = (DWORD)FTP_strdup(lpszFileName); | |
| return INTERNET_AsyncCall(&workRequest); | |
| } | |
| else | |
| { | |
| return FTP_FtpDeleteFileA(hFtpSession, lpszFileName); | |
| } | |
| } | |
| /*********************************************************************** | |
| * FTP_FtpDeleteFileA (Internal) | |
| * | |
| * Delete a file on the ftp server | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * FALSE on failure | |
| * | |
| */ | |
| BOOL FTP_FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName) | |
| { | |
| INT nResCode; | |
| BOOL bSuccess = FALSE; | |
| LPWININETAPPINFOA hIC = NULL; | |
| LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession; | |
| TRACE("0x%08lx\n", (ULONG) hFtpSession); | |
| if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype) | |
| { | |
| INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); | |
| return FALSE; | |
| } | |
| /* Clear any error information */ | |
| INTERNET_SetLastError(0); | |
| if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0)) | |
| goto lend; | |
| nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), | |
| MAX_REPLY_LEN, 0, 0, 0); | |
| if (nResCode) | |
| { | |
| if (nResCode == 250) | |
| bSuccess = TRUE; | |
| else | |
| FTP_SetResponseError(nResCode); | |
| } | |
| lend: | |
| hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent; | |
| if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB) | |
| { | |
| INTERNET_ASYNC_RESULT iar; | |
| iar.dwResult = (DWORD)bSuccess; | |
| iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError(); | |
| hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, | |
| &iar, sizeof(INTERNET_ASYNC_RESULT)); | |
| } | |
| return bSuccess; | |
| } | |
| /*********************************************************************** | |
| * FtpRemoveDirectoryA (WININET.@) | |
| * | |
| * Remove a directory on the ftp server | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * FALSE on failure | |
| * | |
| */ | |
| BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory) | |
| { | |
| LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession; | |
| LPWININETAPPINFOA hIC = NULL; | |
| if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype) | |
| { | |
| INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); | |
| return FALSE; | |
| } | |
| hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent; | |
| if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) | |
| { | |
| WORKREQUEST workRequest; | |
| workRequest.asyncall = FTPREMOVEDIRECTORYA; | |
| workRequest.HFTPSESSION = (DWORD)hFtpSession; | |
| workRequest.LPSZDIRECTORY = (DWORD)FTP_strdup(lpszDirectory); | |
| return INTERNET_AsyncCall(&workRequest); | |
| } | |
| else | |
| { | |
| return FTP_FtpRemoveDirectoryA(hFtpSession, lpszDirectory); | |
| } | |
| } | |
| /*********************************************************************** | |
| * FTP_FtpRemoveDirectoryA (Internal) | |
| * | |
| * Remove a directory on the ftp server | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * FALSE on failure | |
| * | |
| */ | |
| BOOL FTP_FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory) | |
| { | |
| INT nResCode; | |
| BOOL bSuccess = FALSE; | |
| LPWININETAPPINFOA hIC = NULL; | |
| LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession; | |
| TRACE("\n"); | |
| if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype) | |
| { | |
| INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); | |
| return FALSE; | |
| } | |
| /* Clear any error information */ | |
| INTERNET_SetLastError(0); | |
| if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0)) | |
| goto lend; | |
| nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), | |
| MAX_REPLY_LEN, 0, 0, 0); | |
| if (nResCode) | |
| { | |
| if (nResCode == 250) | |
| bSuccess = TRUE; | |
| else | |
| FTP_SetResponseError(nResCode); | |
| } | |
| lend: | |
| hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent; | |
| if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB) | |
| { | |
| INTERNET_ASYNC_RESULT iar; | |
| iar.dwResult = (DWORD)bSuccess; | |
| iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError(); | |
| hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, | |
| &iar, sizeof(INTERNET_ASYNC_RESULT)); | |
| } | |
| return bSuccess; | |
| } | |
| /*********************************************************************** | |
| * FtpRenameFileA (WININET.@) | |
| * | |
| * Rename a file on the ftp server | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * FALSE on failure | |
| * | |
| */ | |
| BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest) | |
| { | |
| LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession; | |
| LPWININETAPPINFOA hIC = NULL; | |
| if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype) | |
| { | |
| INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); | |
| return FALSE; | |
| } | |
| hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent; | |
| if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC) | |
| { | |
| WORKREQUEST workRequest; | |
| workRequest.asyncall = FTPRENAMEFILEA; | |
| workRequest.HFTPSESSION = (DWORD)hFtpSession; | |
| workRequest.LPSZSRCFILE = (DWORD)FTP_strdup(lpszSrc); | |
| workRequest.LPSZDESTFILE = (DWORD)FTP_strdup(lpszDest); | |
| return INTERNET_AsyncCall(&workRequest); | |
| } | |
| else | |
| { | |
| return FTP_FtpRenameFileA(hFtpSession, lpszSrc, lpszDest); | |
| } | |
| } | |
| /*********************************************************************** | |
| * FTP_FtpRenameFileA (Internal) | |
| * | |
| * Rename a file on the ftp server | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * FALSE on failure | |
| * | |
| */ | |
| BOOL FTP_FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest) | |
| { | |
| INT nResCode; | |
| BOOL bSuccess = FALSE; | |
| LPWININETAPPINFOA hIC = NULL; | |
| LPWININETFTPSESSIONA lpwfs = (LPWININETFTPSESSIONA) hFtpSession; | |
| TRACE("\n"); | |
| if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype) | |
| { | |
| INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); | |
| return FALSE; | |
| } | |
| /* Clear any error information */ | |
| INTERNET_SetLastError(0); | |
| if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0)) | |
| goto lend; | |
| nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, | |
| INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0); | |
| if (nResCode == 350) | |
| { | |
| if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0)) | |
| goto lend; | |
| nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, | |
| INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0); | |
| } | |
| if (nResCode == 250) | |
| bSuccess = TRUE; | |
| else | |
| FTP_SetResponseError(nResCode); | |
| lend: | |
| hIC = (LPWININETAPPINFOA) lpwfs->hdr.lpwhparent; | |
| if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB) | |
| { | |
| INTERNET_ASYNC_RESULT iar; | |
| iar.dwResult = (DWORD)bSuccess; | |
| iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError(); | |
| hIC->lpfnStatusCB(hFtpSession, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, | |
| &iar, sizeof(INTERNET_ASYNC_RESULT)); | |
| } | |
| return bSuccess; | |
| } | |
| /*********************************************************************** | |
| * FTP_Connect (internal) | |
| * | |
| * Connect to a ftp server | |
| * | |
| * RETURNS | |
| * HINTERNET a session handle on success | |
| * NULL on failure | |
| * | |
| */ | |
| HINTERNET FTP_Connect(HINTERNET hInternet, LPCSTR lpszServerName, | |
| INTERNET_PORT nServerPort, LPCSTR lpszUserName, | |
| LPCSTR lpszPassword, DWORD dwFlags, DWORD dwContext) | |
| { | |
| struct sockaddr_in socketAddr; | |
| struct hostent *phe = NULL; | |
| INT nsocket = -1, sock_namelen; | |
| LPWININETAPPINFOA hIC = NULL; | |
| BOOL bSuccess = FALSE; | |
| LPWININETFTPSESSIONA lpwfs = NULL; | |
| TRACE("0x%08lx Server(%s) Port(%d) User(%s) Paswd(%s)\n", | |
| (ULONG) hInternet, lpszServerName, | |
| nServerPort, lpszUserName, lpszPassword); | |
| if (((LPWININETHANDLEHEADER)hInternet)->htype != WH_HINIT) | |
| goto lerror; | |
| hIC = (LPWININETAPPINFOA) hInternet; | |
| if (NULL == lpszUserName && NULL != lpszPassword) | |
| { | |
| INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_USER_NAME); | |
| goto lerror; | |
| } | |
| if (nServerPort == INTERNET_INVALID_PORT_NUMBER) | |
| nServerPort = INTERNET_DEFAULT_FTP_PORT; | |
| if (hIC->lpfnStatusCB) | |
| hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_RESOLVING_NAME, | |
| (LPSTR) lpszServerName, strlen(lpszServerName)); | |
| if (!GetAddress(lpszServerName, nServerPort, &phe, &socketAddr)) | |
| { | |
| INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED); | |
| goto lerror; | |
| } | |
| if (hIC->lpfnStatusCB) | |
| hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_NAME_RESOLVED, | |
| (LPSTR) lpszServerName, strlen(lpszServerName)); | |
| nsocket = socket(AF_INET,SOCK_STREAM,0); | |
| if (nsocket == -1) | |
| { | |
| INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT); | |
| goto lerror; | |
| } | |
| if (hIC->lpfnStatusCB) | |
| hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER, | |
| &socketAddr, sizeof(struct sockaddr_in)); | |
| if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0) | |
| { | |
| ERR("Unable to connect (%s)\n", strerror(errno)); | |
| INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT); | |
| } | |
| else | |
| { | |
| TRACE("Connected to server\n"); | |
| if (hIC->lpfnStatusCB) | |
| hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER, | |
| &socketAddr, sizeof(struct sockaddr_in)); | |
| lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONA)); | |
| if (NULL == lpwfs) | |
| { | |
| INTERNET_SetLastError(ERROR_OUTOFMEMORY); | |
| goto lerror; | |
| } | |
| lpwfs->hdr.htype = WH_HFTPSESSION; | |
| lpwfs->hdr.dwFlags = dwFlags; | |
| lpwfs->hdr.dwContext = dwContext; | |
| lpwfs->hdr.lpwhparent = (LPWININETHANDLEHEADER)hInternet; | |
| lpwfs->sndSocket = nsocket; | |
| sock_namelen = sizeof(lpwfs->socketAddress); | |
| getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen); | |
| lpwfs->phostent = phe; | |
| if (NULL == lpszUserName) | |
| { | |
| lpwfs->lpszUserName = FTP_strdup("anonymous"); | |
| lpwfs->lpszPassword = FTP_strdup("user@server"); | |
| } | |
| else | |
| { | |
| lpwfs->lpszUserName = FTP_strdup(lpszUserName); | |
| lpwfs->lpszPassword = FTP_strdup(lpszPassword); | |
| } | |
| if (FTP_ConnectToHost(lpwfs)) | |
| { | |
| if (hIC->lpfnStatusCB) | |
| { | |
| INTERNET_ASYNC_RESULT iar; | |
| iar.dwResult = (DWORD)lpwfs; | |
| iar.dwError = ERROR_SUCCESS; | |
| hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_HANDLE_CREATED, | |
| &iar, sizeof(INTERNET_ASYNC_RESULT)); | |
| } | |
| TRACE("Successfully logged into server\n"); | |
| bSuccess = TRUE; | |
| } | |
| } | |
| lerror: | |
| if (!bSuccess && nsocket == -1) | |
| close(nsocket); | |
| if (!bSuccess && lpwfs) | |
| { | |
| HeapFree(GetProcessHeap(), 0, lpwfs); | |
| lpwfs = NULL; | |
| } | |
| if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB) | |
| { | |
| INTERNET_ASYNC_RESULT iar; | |
| iar.dwResult = (DWORD)lpwfs; | |
| iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError(); | |
| hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_REQUEST_COMPLETE, | |
| &iar, sizeof(INTERNET_ASYNC_RESULT)); | |
| } | |
| return (HINTERNET) lpwfs; | |
| } | |
| /*********************************************************************** | |
| * FTP_ConnectToHost (internal) | |
| * | |
| * Connect to a ftp server | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * NULL on failure | |
| * | |
| */ | |
| BOOL FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs) | |
| { | |
| INT nResCode; | |
| BOOL bSuccess = FALSE; | |
| TRACE("\n"); | |
| FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), MAX_REPLY_LEN, 0, 0, 0); | |
| if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0)) | |
| goto lend; | |
| nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), | |
| MAX_REPLY_LEN, 0, 0, 0); | |
| if (nResCode) | |
| { | |
| /* Login successful... */ | |
| if (nResCode == 230) | |
| bSuccess = TRUE; | |
| /* User name okay, need password... */ | |
| else if (nResCode == 331) | |
| bSuccess = FTP_SendPassword(lpwfs); | |
| /* Need account for login... */ | |
| else if (nResCode == 332) | |
| bSuccess = FTP_SendAccount(lpwfs); | |
| else | |
| FTP_SetResponseError(nResCode); | |
| } | |
| TRACE("Returning %d\n", bSuccess); | |
| lend: | |
| return bSuccess; | |
| } | |
| /*********************************************************************** | |
| * FTP_SendCommand (internal) | |
| * | |
| * Send command to server | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * NULL on failure | |
| * | |
| */ | |
| BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam, | |
| INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext) | |
| { | |
| DWORD len; | |
| CHAR *buf; | |
| DWORD nBytesSent = 0; | |
| DWORD nRC = 0; | |
| BOOL bParamHasLen; | |
| TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket); | |
| if (lpfnStatusCB) | |
| lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0); | |
| bParamHasLen = lpszParam && strlen(lpszParam) > 0; | |
| len = (bParamHasLen ? strlen(lpszParam) : -1) + strlen(szFtpCommands[ftpCmd]) + | |
| strlen(szCRLF)+ 1; | |
| if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1))) | |
| { | |
| INTERNET_SetLastError(ERROR_OUTOFMEMORY); | |
| return FALSE; | |
| } | |
| sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], bParamHasLen ? " " : "", | |
| bParamHasLen ? lpszParam : "", szCRLF); | |
| TRACE("Sending (%s) len(%ld)\n", buf, len); | |
| while((nBytesSent < len) && (nRC != -1)) | |
| { | |
| nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0); | |
| nBytesSent += nRC; | |
| } | |
| HeapFree(GetProcessHeap(), 0, (LPVOID)buf); | |
| if (lpfnStatusCB) | |
| lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_REQUEST_SENT, | |
| &nBytesSent, sizeof(DWORD)); | |
| TRACE("Sent %ld bytes\n", nBytesSent); | |
| return (nRC != -1); | |
| } | |
| /*********************************************************************** | |
| * FTP_ReceiveResponse (internal) | |
| * | |
| * Receive response from server | |
| * | |
| * RETURNS | |
| * Reply code on success | |
| * 0 on failure | |
| * | |
| */ | |
| INT FTP_ReceiveResponse(INT nSocket, LPSTR lpszResponse, DWORD dwResponse, | |
| INTERNET_STATUS_CALLBACK lpfnStatusCB, HINTERNET hHandle, DWORD dwContext) | |
| { | |
| DWORD nRecv; | |
| INT rc = 0; | |
| char firstprefix[5]; | |
| BOOL multiline = FALSE; | |
| TRACE("socket(%d) \n", nSocket); | |
| if (lpfnStatusCB) | |
| lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); | |
| while(1) | |
| { | |
| nRecv = dwResponse; | |
| if (!INTERNET_GetNextLine(nSocket, lpszResponse, &nRecv)) | |
| goto lerror; | |
| if (nRecv >= 3) | |
| { | |
| if(!multiline) | |
| { | |
| if(lpszResponse[3] != '-') | |
| break; | |
| else | |
| { /* Start of multiline repsonse. Loop until we get "nnn " */ | |
| multiline = TRUE; | |
| memcpy(firstprefix, lpszResponse, 3); | |
| firstprefix[3] = ' '; | |
| firstprefix[4] = '\0'; | |
| } | |
| } | |
| else | |
| { | |
| if(!memcmp(firstprefix, lpszResponse, 4)) | |
| break; | |
| } | |
| } | |
| } | |
| if (nRecv >= 3) | |
| { | |
| lpszResponse[nRecv] = '\0'; | |
| rc = atoi(lpszResponse); | |
| if (lpfnStatusCB) | |
| lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED, | |
| &nRecv, sizeof(DWORD)); | |
| } | |
| lerror: | |
| TRACE("return %d\n", rc); | |
| return rc; | |
| } | |
| /*********************************************************************** | |
| * FTP_SendPassword (internal) | |
| * | |
| * Send password to ftp server | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * NULL on failure | |
| * | |
| */ | |
| BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs) | |
| { | |
| INT nResCode; | |
| BOOL bSuccess = FALSE; | |
| TRACE("\n"); | |
| if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0)) | |
| goto lend; | |
| nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), | |
| MAX_REPLY_LEN, 0, 0, 0); | |
| if (nResCode) | |
| { | |
| TRACE("Received reply code %d\n", nResCode); | |
| /* Login successful... */ | |
| if (nResCode == 230) | |
| bSuccess = TRUE; | |
| /* Command not implemented, superfluous at the server site... */ | |
| /* Need account for login... */ | |
| else if (nResCode == 332) | |
| bSuccess = FTP_SendAccount(lpwfs); | |
| else | |
| FTP_SetResponseError(nResCode); | |
| } | |
| lend: | |
| TRACE("Returning %d\n", bSuccess); | |
| return bSuccess; | |
| } | |
| /*********************************************************************** | |
| * FTP_SendAccount (internal) | |
| * | |
| * | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * FALSE on failure | |
| * | |
| */ | |
| BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs) | |
| { | |
| INT nResCode; | |
| BOOL bSuccess = FALSE; | |
| TRACE("\n"); | |
| if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, NOACCOUNT, 0, 0, 0)) | |
| goto lend; | |
| nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), | |
| MAX_REPLY_LEN, 0, 0, 0); | |
| if (nResCode) | |
| bSuccess = TRUE; | |
| else | |
| FTP_SetResponseError(nResCode); | |
| lend: | |
| return bSuccess; | |
| } | |
| /*********************************************************************** | |
| * FTP_SendStore (internal) | |
| * | |
| * Send request to upload file to ftp server | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * FALSE on failure | |
| * | |
| */ | |
| BOOL FTP_SendStore(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType) | |
| { | |
| INT nResCode; | |
| BOOL bSuccess = FALSE; | |
| TRACE("\n"); | |
| if (!FTP_InitListenSocket(lpwfs)) | |
| goto lend; | |
| if (!FTP_SendType(lpwfs, dwType)) | |
| goto lend; | |
| if (!FTP_SendPortOrPasv(lpwfs)) | |
| goto lend; | |
| if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0)) | |
| goto lend; | |
| nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), | |
| MAX_REPLY_LEN, 0, 0, 0); | |
| if (nResCode) | |
| { | |
| if (nResCode == 150) | |
| bSuccess = TRUE; | |
| else | |
| FTP_SetResponseError(nResCode); | |
| } | |
| lend: | |
| if (!bSuccess && lpwfs->lstnSocket != -1) | |
| { | |
| close(lpwfs->lstnSocket); | |
| lpwfs->lstnSocket = -1; | |
| } | |
| return bSuccess; | |
| } | |
| /*********************************************************************** | |
| * FTP_InitListenSocket (internal) | |
| * | |
| * Create a socket to listen for server response | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * FALSE on failure | |
| * | |
| */ | |
| BOOL FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs) | |
| { | |
| BOOL bSuccess = FALSE; | |
| size_t namelen = sizeof(struct sockaddr_in); | |
| TRACE("\n"); | |
| lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0); | |
| if (lpwfs->lstnSocket == -1) | |
| { | |
| TRACE("Unable to create listening socket\n"); | |
| goto lend; | |
| } | |
| /* We obtain our ip addr from the name of the command channel socket */ | |
| lpwfs->lstnSocketAddress = lpwfs->socketAddress; | |
| /* and get the system to assign us a port */ | |
| lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0); | |
| if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1) | |
| { | |
| TRACE("Unable to bind socket\n"); | |
| goto lend; | |
| } | |
| if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1) | |
| { | |
| TRACE("listen failed\n"); | |
| goto lend; | |
| } | |
| if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1) | |
| bSuccess = TRUE; | |
| lend: | |
| if (!bSuccess && lpwfs->lstnSocket == -1) | |
| { | |
| close(lpwfs->lstnSocket); | |
| lpwfs->lstnSocket = -1; | |
| } | |
| return bSuccess; | |
| } | |
| /*********************************************************************** | |
| * FTP_SendType (internal) | |
| * | |
| * Tell server type of data being transferred | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * FALSE on failure | |
| * | |
| * W98SE doesn't cache the type that's currently set | |
| * (i.e. it sends it always), | |
| * so we probably don't want to do that either. | |
| */ | |
| BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType) | |
| { | |
| INT nResCode; | |
| CHAR type[2] = { "I\0" }; | |
| BOOL bSuccess = FALSE; | |
| TRACE("\n"); | |
| if (dwType & INTERNET_FLAG_TRANSFER_ASCII) | |
| *type = 'A'; | |
| if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0)) | |
| goto lend; | |
| nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), | |
| MAX_REPLY_LEN, 0, 0, 0)/100; | |
| if (nResCode) | |
| { | |
| if (nResCode == 2) | |
| bSuccess = TRUE; | |
| else | |
| FTP_SetResponseError(nResCode); | |
| } | |
| lend: | |
| return bSuccess; | |
| } | |
| /*********************************************************************** | |
| * FTP_SendPort (internal) | |
| * | |
| * Tell server which port to use | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * FALSE on failure | |
| * | |
| */ | |
| BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs) | |
| { | |
| INT nResCode; | |
| CHAR szIPAddress[64]; | |
| BOOL bSuccess = FALSE; | |
| TRACE("\n"); | |
| sprintf(szIPAddress, "%d,%d,%d,%d,%d,%d", | |
| lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF, | |
| (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8, | |
| (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16, | |
| (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24, | |
| lpwfs->lstnSocketAddress.sin_port & 0xFF, | |
| (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8); | |
| if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0)) | |
| goto lend; | |
| nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), | |
| MAX_REPLY_LEN,0, 0, 0); | |
| if (nResCode) | |
| { | |
| if (nResCode == 200) | |
| bSuccess = TRUE; | |
| else | |
| FTP_SetResponseError(nResCode); | |
| } | |
| lend: | |
| return bSuccess; | |
| } | |
| /*********************************************************************** | |
| * FTP_DoPassive (internal) | |
| * | |
| * Tell server that we want to do passive transfers | |
| * and connect data socket | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * FALSE on failure | |
| * | |
| */ | |
| BOOL FTP_DoPassive(LPWININETFTPSESSIONA lpwfs) | |
| { | |
| INT nResCode; | |
| BOOL bSuccess = FALSE; | |
| TRACE("\n"); | |
| if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0)) | |
| goto lend; | |
| nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), | |
| MAX_REPLY_LEN,0, 0, 0); | |
| if (nResCode) | |
| { | |
| if (nResCode == 227) | |
| { | |
| LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer(); | |
| LPSTR p; | |
| int f[6]; | |
| int i; | |
| char *pAddr, *pPort; | |
| INT nsocket = -1; | |
| struct sockaddr_in dataSocketAddress; | |
| p = lpszResponseBuffer+4; /* skip status code */ | |
| /* do a very strict check; we can improve that later. */ | |
| if (strncmp(p, "Entering Passive Mode", 21)) | |
| { | |
| ERR("unknown response '%.*s', aborting\n", 21, p); | |
| goto lend; | |
| } | |
| p += 21; /* skip string */ | |
| if ((*p++ != ' ') || (*p++ != '(')) | |
| { | |
| ERR("unknown response format, aborting\n"); | |
| goto lend; | |
| } | |
| if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3], | |
| &f[4], &f[5]) != 6) | |
| { | |
| ERR("unknown response address format '%s', aborting\n", p); | |
| goto lend; | |
| } | |
| for (i=0; i < 6; i++) | |
| f[i] = f[i] & 0xff; | |
| dataSocketAddress = lpwfs->socketAddress; | |
| pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr); | |
| pPort = (char *)&(dataSocketAddress.sin_port); | |
| pAddr[0] = f[0]; | |
| pAddr[1] = f[1]; | |
| pAddr[2] = f[2]; | |
| pAddr[3] = f[3]; | |
| pPort[0] = f[4]; | |
| pPort[1] = f[5]; | |
| nsocket = socket(AF_INET,SOCK_STREAM,0); | |
| if (nsocket == -1) | |
| goto lend; | |
| if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress))) | |
| { | |
| ERR("can't connect passive FTP data port.\n"); | |
| goto lend; | |
| } | |
| lpwfs->pasvSocket = nsocket; | |
| bSuccess = TRUE; | |
| } | |
| else | |
| FTP_SetResponseError(nResCode); | |
| } | |
| lend: | |
| return bSuccess; | |
| } | |
| BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs) | |
| { | |
| if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE) | |
| { | |
| if (!FTP_DoPassive(lpwfs)) | |
| return FALSE; | |
| } | |
| else | |
| { | |
| if (!FTP_SendPort(lpwfs)) | |
| return FALSE; | |
| } | |
| return TRUE; | |
| } | |
| /*********************************************************************** | |
| * FTP_GetDataSocket (internal) | |
| * | |
| * Either accepts an incoming data socket connection from the server | |
| * or just returns the already opened socket after a PASV command | |
| * in case of passive FTP. | |
| * | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * FALSE on failure | |
| * | |
| */ | |
| BOOL FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs, LPINT nDataSocket) | |
| { | |
| struct sockaddr_in saddr; | |
| size_t addrlen = sizeof(struct sockaddr); | |
| TRACE("\n"); | |
| if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE) | |
| { | |
| *nDataSocket = lpwfs->pasvSocket; | |
| } | |
| else | |
| { | |
| *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen); | |
| close(lpwfs->lstnSocket); | |
| lpwfs->lstnSocket = -1; | |
| } | |
| return *nDataSocket != -1; | |
| } | |
| /*********************************************************************** | |
| * FTP_SendData (internal) | |
| * | |
| * Send data to the server | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * FALSE on failure | |
| * | |
| */ | |
| BOOL FTP_SendData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, HANDLE hFile) | |
| { | |
| BY_HANDLE_FILE_INFORMATION fi; | |
| DWORD nBytesRead = 0; | |
| DWORD nBytesSent = 0; | |
| DWORD nTotalSent = 0; | |
| DWORD nBytesToSend, nLen, nRC = 1; | |
| time_t s_long_time, e_long_time; | |
| LONG nSeconds; | |
| CHAR *lpszBuffer; | |
| TRACE("\n"); | |
| lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE); | |
| memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE); | |
| /* Get the size of the file. */ | |
| GetFileInformationByHandle(hFile, &fi); | |
| time(&s_long_time); | |
| do | |
| { | |
| nBytesToSend = nBytesRead - nBytesSent; | |
| if (nBytesToSend <= 0) | |
| { | |
| /* Read data from file. */ | |
| nBytesSent = 0; | |
| if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0)) | |
| ERR("Failed reading from file\n"); | |
| if (nBytesRead > 0) | |
| nBytesToSend = nBytesRead; | |
| else | |
| break; | |
| } | |
| nLen = DATA_PACKET_SIZE < nBytesToSend ? | |
| DATA_PACKET_SIZE : nBytesToSend; | |
| nRC = send(nDataSocket, lpszBuffer, nLen, 0); | |
| if (nRC != -1) | |
| { | |
| nBytesSent += nRC; | |
| nTotalSent += nRC; | |
| } | |
| /* Do some computation to display the status. */ | |
| time(&e_long_time); | |
| nSeconds = e_long_time - s_long_time; | |
| if( nSeconds / 60 > 0 ) | |
| { | |
| TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld min %ld sec estimated remainig time %ld sec\n", | |
| nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60, | |
| nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent ); | |
| } | |
| else | |
| { | |
| TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld sec estimated remainig time %ld sec\n", | |
| nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds, | |
| (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent); | |
| } | |
| } while (nRC != -1); | |
| TRACE("file transfer complete!\n"); | |
| if(lpszBuffer != NULL) | |
| HeapFree(GetProcessHeap(), 0, lpszBuffer); | |
| return nTotalSent; | |
| } | |
| /*********************************************************************** | |
| * FTP_SendRetrieve (internal) | |
| * | |
| * Send request to retrieve a file | |
| * | |
| * RETURNS | |
| * Number of bytes to be received on success | |
| * 0 on failure | |
| * | |
| */ | |
| DWORD FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD dwType) | |
| { | |
| INT nResCode; | |
| DWORD nResult = 0; | |
| TRACE("\n"); | |
| if (!FTP_InitListenSocket(lpwfs)) | |
| goto lend; | |
| if (!FTP_SendType(lpwfs, dwType)) | |
| goto lend; | |
| if (!FTP_SendPortOrPasv(lpwfs)) | |
| goto lend; | |
| if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0)) | |
| goto lend; | |
| nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(), | |
| MAX_REPLY_LEN, 0, 0, 0); | |
| if (nResCode) | |
| { | |
| if (nResCode == 125 || nResCode == 150) | |
| { | |
| /* Parse size of data to be retrieved */ | |
| INT i, sizepos = -1; | |
| LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer(); | |
| for (i = strlen(lpszResponseBuffer) - 1; i >= 0; i--) | |
| { | |
| if ('(' == lpszResponseBuffer[i]) | |
| { | |
| sizepos = i; | |
| break; | |
| } | |
| } | |
| if (sizepos >= 0) | |
| { | |
| nResult = atol(&lpszResponseBuffer[sizepos+1]); | |
| TRACE("Waiting to receive %ld bytes\n", nResult); | |
| } | |
| } | |
| } | |
| lend: | |
| if (0 == nResult && lpwfs->lstnSocket != -1) | |
| { | |
| close(lpwfs->lstnSocket); | |
| lpwfs->lstnSocket = -1; | |
| } | |
| return nResult; | |
| } | |
| /*********************************************************************** | |
| * FTP_RetrieveData (internal) | |
| * | |
| * Retrieve data from server | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * FALSE on failure | |
| * | |
| */ | |
| BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile) | |
| { | |
| DWORD nBytesWritten; | |
| DWORD nBytesReceived = 0; | |
| INT nRC = 0; | |
| CHAR *lpszBuffer; | |
| TRACE("\n"); | |
| if (INVALID_HANDLE_VALUE == hFile) | |
| return FALSE; | |
| lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE); | |
| if (NULL == lpszBuffer) | |
| { | |
| INTERNET_SetLastError(ERROR_OUTOFMEMORY); | |
| return FALSE; | |
| } | |
| while (nBytesReceived < nBytes && nRC != -1) | |
| { | |
| nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0); | |
| if (nRC != -1) | |
| { | |
| /* other side closed socket. */ | |
| if (nRC == 0) | |
| goto recv_end; | |
| WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL); | |
| nBytesReceived += nRC; | |
| } | |
| TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived, nBytes, | |
| nBytesReceived * 100 / nBytes); | |
| } | |
| TRACE("Data transfer complete\n"); | |
| if (NULL != lpszBuffer) | |
| HeapFree(GetProcessHeap(), 0, lpszBuffer); | |
| recv_end: | |
| return (nRC != -1); | |
| } | |
| /*********************************************************************** | |
| * FTP_CloseSessionHandle (internal) | |
| * | |
| * Deallocate session handle | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * FALSE on failure | |
| * | |
| */ | |
| BOOL FTP_CloseSessionHandle(LPWININETFTPSESSIONA lpwfs) | |
| { | |
| if (lpwfs->sndSocket != -1) | |
| close(lpwfs->sndSocket); | |
| if (lpwfs->lstnSocket != -1) | |
| close(lpwfs->lstnSocket); | |
| if (lpwfs->lpszPassword) | |
| HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword); | |
| if (lpwfs->lpszUserName) | |
| HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName); | |
| HeapFree(GetProcessHeap(), 0, lpwfs); | |
| return TRUE; | |
| } | |
| /*********************************************************************** | |
| * FTP_CloseSessionHandle (internal) | |
| * | |
| * Deallocate session handle | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * FALSE on failure | |
| * | |
| */ | |
| BOOL FTP_CloseFindNextHandle(LPWININETFINDNEXTA lpwfn) | |
| { | |
| INT i; | |
| TRACE("\n"); | |
| for (i = 0; i < lpwfn->size; i++) | |
| { | |
| if (NULL != lpwfn->lpafp[i].lpszName) | |
| HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName); | |
| } | |
| HeapFree(GetProcessHeap(), 0, lpwfn->lpafp); | |
| HeapFree(GetProcessHeap(), 0, lpwfn); | |
| return TRUE; | |
| } | |
| /*********************************************************************** | |
| * FTP_ReceiveFileList (internal) | |
| * | |
| * Read file list from server | |
| * | |
| * RETURNS | |
| * Handle to file list on success | |
| * NULL on failure | |
| * | |
| */ | |
| HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs, INT nSocket, | |
| LPWIN32_FIND_DATAA lpFindFileData, DWORD dwContext) | |
| { | |
| DWORD dwSize = 0; | |
| LPFILEPROPERTIESA lpafp = NULL; | |
| LPWININETFINDNEXTA lpwfn = NULL; | |
| TRACE("\n"); | |
| if (FTP_ParseDirectory(lpwfs, nSocket, &lpafp, &dwSize)) | |
| { | |
| FTP_ConvertFileProp(lpafp, lpFindFileData); | |
| lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFINDNEXTA)); | |
| if (NULL != lpwfn) | |
| { | |
| lpwfn->hdr.htype = WH_HFINDNEXT; | |
| lpwfn->hdr.lpwhparent = (LPWININETHANDLEHEADER)lpwfs; | |
| lpwfn->hdr.dwContext = dwContext; | |
| lpwfn->index = 1; /* Next index is 1 since we return index 0 */ | |
| lpwfn->size = dwSize; | |
| lpwfn->lpafp = lpafp; | |
| } | |
| } | |
| TRACE("Matched %ld files\n", dwSize); | |
| return (HINTERNET)lpwfn; | |
| } | |
| /*********************************************************************** | |
| * FTP_ConvertFileProp (internal) | |
| * | |
| * Converts FILEPROPERTIESA struct to WIN32_FIND_DATAA | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * FALSE on failure | |
| * | |
| */ | |
| BOOL FTP_ConvertFileProp(LPFILEPROPERTIESA lpafp, LPWIN32_FIND_DATAA lpFindFileData) | |
| { | |
| BOOL bSuccess = FALSE; | |
| ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA)); | |
| if (lpafp) | |
| { | |
| DWORD access = mktime(&lpafp->tmLastModified); | |
| /* Not all fields are filled in */ | |
| lpFindFileData->ftLastAccessTime.dwHighDateTime = HIWORD(access); | |
| lpFindFileData->ftLastAccessTime.dwLowDateTime = LOWORD(access); | |
| lpFindFileData->nFileSizeHigh = HIWORD(lpafp->nSize); | |
| lpFindFileData->nFileSizeLow = LOWORD(lpafp->nSize); | |
| if (lpafp->bIsDirectory) | |
| lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY; | |
| if (lpafp->lpszName) | |
| strncpy(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH); | |
| bSuccess = TRUE; | |
| } | |
| return bSuccess; | |
| } | |
| /*********************************************************************** | |
| * FTP_ParseDirectory (internal) | |
| * | |
| * Parse string of directory information | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * FALSE on failure | |
| * | |
| * FIXME: - This function needs serious clea-up | |
| * - We should consider both UNIX and NT list formats | |
| */ | |
| #define MAX_MONTH_LEN 10 | |
| #define MIN_LEN_DIR_ENTRY 15 | |
| BOOL FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs, INT nSocket, LPFILEPROPERTIESA *lpafp, LPDWORD dwfp) | |
| { | |
| /* | |
| * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename> | |
| * | |
| * For instance: | |
| * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier | |
| */ | |
| CHAR* pszMinutes; | |
| CHAR* pszHour; | |
| time_t aTime; | |
| struct tm* apTM; | |
| CHAR pszMonth[MAX_MONTH_LEN]; | |
| CHAR* pszMatch; | |
| BOOL bSuccess = TRUE; | |
| DWORD nBufLen = MAX_REPLY_LEN; | |
| LPFILEPROPERTIESA curFileProp = NULL; | |
| CHAR* pszLine = NULL; | |
| CHAR* pszToken = NULL; | |
| INT nTokenToSkip = 3; | |
| INT nCount = 0; | |
| INT nSeconds = 0; | |
| INT nMinutes = 0; | |
| INT nHour = 0; | |
| INT nDay = 0; | |
| INT nMonth = 0; | |
| INT nYear = 0; | |
| INT sizeFilePropArray = 20; | |
| INT indexFilePropArray = 0; | |
| TRACE("\n"); | |
| /* Allocate intial file properties array */ | |
| *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESA)*(sizeFilePropArray)); | |
| if (NULL == lpafp) | |
| { | |
| bSuccess = FALSE; | |
| goto lend; | |
| } | |
| while ((pszLine = INTERNET_GetNextLine(nSocket, INTERNET_GetResponseBuffer(), &nBufLen)) != NULL) | |
| { | |
| if (sizeFilePropArray <= indexFilePropArray) | |
| { | |
| LPFILEPROPERTIESA tmpafp; | |
| sizeFilePropArray *= 2; | |
| tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp, | |
| sizeof(FILEPROPERTIESA)*sizeFilePropArray); | |
| if (NULL == tmpafp) | |
| { | |
| bSuccess = FALSE; | |
| goto lend; | |
| } | |
| *lpafp = tmpafp; | |
| } | |
| curFileProp = &((*lpafp)[indexFilePropArray]); | |
| /* First Parse the permissions. */ | |
| pszToken = strtok(pszLine, " \t" ); | |
| /* HACK! If this is not a file listing skip the line */ | |
| if (!pszToken || 10 != strlen(pszToken) || nBufLen <= MIN_LEN_DIR_ENTRY) | |
| { | |
| nBufLen = MAX_REPLY_LEN; | |
| continue; | |
| } | |
| FTP_ParsePermission(pszToken, curFileProp); | |
| nTokenToSkip = 3; | |
| nCount = 0; | |
| do | |
| { | |
| pszToken = strtok( NULL, " \t" ); | |
| nCount++; | |
| } while( nCount <= nTokenToSkip ); | |
| /* Store the size of the file in the param list. */ | |
| TRACE("nSize-> %s\n", pszToken); | |
| if (pszToken != NULL) | |
| curFileProp->nSize = atol(pszToken); | |
| /* Parse last modified time. */ | |
| nSeconds = 0; | |
| nMinutes = 0; | |
| nHour = 0; | |
| nDay = 0; | |
| nMonth = 0; | |
| nYear = 0; | |
| pszToken = strtok( NULL, " \t" ); | |
| strncpy(pszMonth, pszToken, MAX_MONTH_LEN); | |
| CharUpperA(pszMonth); | |
| pszMatch = strstr(szMonths, pszMonth); | |
| if( pszMatch != NULL ) | |
| nMonth = (pszMatch - szMonths) / 3; | |
| pszToken = strtok(NULL, " \t"); | |
| TRACE("nDay -> %s\n", pszToken); | |
| if (pszToken != NULL) | |
| nDay = atoi(pszToken); | |
| pszToken = strtok(NULL, " \t"); | |
| pszMinutes = strchr(pszToken, ':'); | |
| if( pszMinutes != NULL ) | |
| { | |
| pszMinutes++; | |
| nMinutes = atoi(pszMinutes); | |
| pszHour = pszMinutes - 3; | |
| if (pszHour != NULL) | |
| nHour = atoi(pszHour); | |
| time(&aTime); | |
| apTM = localtime( &aTime ); | |
| nYear = apTM->tm_year; | |
| } | |
| else | |
| { | |
| nYear = atoi(pszToken); | |
| nYear -= 1900; | |
| nHour = 12; | |
| } | |
| curFileProp->tmLastModified.tm_sec = nSeconds; | |
| curFileProp->tmLastModified.tm_min = nMinutes; | |
| curFileProp->tmLastModified.tm_hour = nHour; | |
| curFileProp->tmLastModified.tm_mday = nDay; | |
| curFileProp->tmLastModified.tm_mon = nMonth; | |
| curFileProp->tmLastModified.tm_year = nYear; | |
| pszToken = strtok(NULL, " \t"); | |
| if(pszToken != NULL) | |
| { | |
| curFileProp->lpszName = FTP_strdup(pszToken); | |
| TRACE(": %s\n", curFileProp->lpszName); | |
| } | |
| nBufLen = MAX_REPLY_LEN; | |
| indexFilePropArray++; | |
| } | |
| if (bSuccess && indexFilePropArray) | |
| { | |
| if (indexFilePropArray < sizeFilePropArray - 1) | |
| { | |
| LPFILEPROPERTIESA tmpafp; | |
| tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp, | |
| sizeof(FILEPROPERTIESA)*indexFilePropArray); | |
| if (NULL == tmpafp) | |
| *lpafp = tmpafp; | |
| } | |
| *dwfp = indexFilePropArray; | |
| } | |
| else | |
| { | |
| HeapFree(GetProcessHeap(), 0, *lpafp); | |
| INTERNET_SetLastError(ERROR_NO_MORE_FILES); | |
| bSuccess = FALSE; | |
| } | |
| lend: | |
| return bSuccess; | |
| } | |
| /*********************************************************************** | |
| * FTP_ParsePermission (internal) | |
| * | |
| * Parse permission string of directory information | |
| * | |
| * RETURNS | |
| * TRUE on success | |
| * FALSE on failure | |
| * | |
| */ | |
| BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESA lpfp) | |
| { | |
| BOOL bSuccess = TRUE; | |
| unsigned short nPermission = 0; | |
| INT nPos = 1; | |
| INT nLast = 9; | |
| TRACE("\n"); | |
| if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l')) | |
| { | |
| bSuccess = FALSE; | |
| return bSuccess; | |
| } | |
| lpfp->bIsDirectory = (*lpszPermission == 'd'); | |
| do | |
| { | |
| switch (nPos) | |
| { | |
| case 1: | |
| nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8; | |
| break; | |
| case 2: | |
| nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7; | |
| break; | |
| case 3: | |
| nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6; | |
| break; | |
| case 4: | |
| nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5; | |
| break; | |
| case 5: | |
| nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4; | |
| break; | |
| case 6: | |
| nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3; | |
| break; | |
| case 7: | |
| nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2; | |
| break; | |
| case 8: | |
| nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1; | |
| break; | |
| case 9: | |
| nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0); | |
| break; | |
| } | |
| nPos++; | |
| }while (nPos <= nLast); | |
| lpfp->permissions = nPermission; | |
| return bSuccess; | |
| } | |
| /*********************************************************************** | |
| * FTP_SetResponseError (internal) | |
| * | |
| * Set the appropriate error code for a given response from the server | |
| * | |
| * RETURNS | |
| * | |
| */ | |
| DWORD FTP_SetResponseError(DWORD dwResponse) | |
| { | |
| DWORD dwCode = 0; | |
| switch(dwResponse) | |
| { | |
| case 421: /* Service not available - Server may be shutting down. */ | |
| dwCode = ERROR_INTERNET_TIMEOUT; | |
| break; | |
| case 425: /* Cannot open data connection. */ | |
| dwCode = ERROR_INTERNET_CANNOT_CONNECT; | |
| break; | |
| case 426: /* Connection closed, transer aborted. */ | |
| dwCode = ERROR_INTERNET_CONNECTION_ABORTED; | |
| break; | |
| case 500: /* Syntax error. Command unrecognized. */ | |
| case 501: /* Syntax error. Error in parameters or arguments. */ | |
| dwCode = ERROR_INTERNET_INCORRECT_FORMAT; | |
| break; | |
| case 530: /* Not logged in. Login incorrect. */ | |
| dwCode = ERROR_INTERNET_LOGIN_FAILURE; | |
| break; | |
| case 550: /* File action not taken. File not found or no access. */ | |
| dwCode = ERROR_INTERNET_ITEM_NOT_FOUND; | |
| break; | |
| case 450: /* File action not taken. File may be busy. */ | |
| case 451: /* Action aborted. Server error. */ | |
| case 452: /* Action not taken. Insufficient storage space on server. */ | |
| case 502: /* Command not implemented. */ | |
| case 503: /* Bad sequence of command. */ | |
| case 504: /* Command not implemented for that parameter. */ | |
| case 532: /* Need account for storing files */ | |
| case 551: /* Requested action aborted. Page type unknown */ | |
| case 552: /* Action aborted. Exceeded storage allocation */ | |
| case 553: /* Action not taken. File name not allowed. */ | |
| default: | |
| dwCode = ERROR_INTERNET_INTERNAL_ERROR; | |
| break; | |
| } | |
| INTERNET_SetLastError(dwCode); | |
| return dwCode; | |
| } |