diff --git a/dlls/wininet/ftp.c b/dlls/wininet/ftp.c index c0452176c58..8c0cc5d7f4c 100644 --- a/dlls/wininet/ftp.c +++ b/dlls/wininet/ftp.c @@ -4,6 +4,7 @@ * Copyright 1999 Corel Corporation * Copyright 2004 Mike McCormack for CodeWeavers * Copyright 2004 Kevin Koltzau + * Copyright 2007 Hans Leidekker * * Ulrich Czekalla * Noureddine Jemmali @@ -1863,10 +1864,34 @@ lend: BOOL WINAPI FtpCommandA( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags, LPCSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand ) { - FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags, + BOOL r; + WCHAR *cmdW; + + TRACE("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags, debugstr_a(lpszCommand), dwContext, phFtpCommand); - return TRUE; + if (fExpectResponse) + { + FIXME("data connection not supported\n"); + return FALSE; + } + + if (!lpszCommand || !lpszCommand[0]) + { + INTERNET_SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (!(cmdW = WININET_strdup_AtoW(lpszCommand))) + { + INTERNET_SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + + r = FtpCommandW(hConnect, fExpectResponse, dwFlags, cmdW, dwContext, phFtpCommand); + + HeapFree(GetProcessHeap(), 0, cmdW); + return r; } /*********************************************************************** @@ -1875,10 +1900,82 @@ BOOL WINAPI FtpCommandA( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags, LPCWSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand ) { - FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags, - debugstr_w(lpszCommand), dwContext, phFtpCommand); + BOOL r = FALSE; + LPWININETFTPSESSIONW lpwfs; + LPSTR cmd = NULL; + DWORD len, nBytesSent= 0; + INT nResCode, nRC = 0; - return TRUE; + TRACE("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags, + debugstr_w(lpszCommand), dwContext, phFtpCommand); + + if (!lpszCommand || !lpszCommand[0]) + { + INTERNET_SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (fExpectResponse) + { + FIXME("data connection not supported\n"); + return FALSE; + } + + lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect ); + if (!lpwfs) + { + INTERNET_SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if (WH_HFTPSESSION != lpwfs->hdr.htype) + { + INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); + goto lend; + } + + if (lpwfs->download_in_progress != NULL) + { + INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS); + goto lend; + } + + len = WideCharToMultiByte(CP_ACP, 0, lpszCommand, -1, NULL, 0, NULL, NULL) + strlen(szCRLF); + if ((cmd = HeapAlloc(GetProcessHeap(), 0, len ))) + WideCharToMultiByte(CP_ACP, 0, lpszCommand, -1, cmd, len, NULL, NULL); + else + { + INTERNET_SetLastError(ERROR_OUTOFMEMORY); + goto lend; + } + + strcat(cmd, szCRLF); + len--; + + TRACE("Sending (%s) len(%d)\n", cmd, len); + while ((nBytesSent < len) && (nRC != -1)) + { + nRC = send(lpwfs->sndSocket, cmd + nBytesSent, len - nBytesSent, 0); + if (nRC != -1) + { + nBytesSent += nRC; + TRACE("Sent %d bytes\n", nRC); + } + } + + if (nBytesSent) + { + nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext); + if (nResCode > 0 && nResCode < 400) + r = TRUE; + else + FTP_SetResponseError(nResCode); + } + +lend: + WININET_Release( &lpwfs->hdr ); + HeapFree(GetProcessHeap(), 0, cmd); + return r; } /*********************************************************************** diff --git a/dlls/wininet/tests/ftp.c b/dlls/wininet/tests/ftp.c index fa13fdc5e30..6d03fb86dcb 100644 --- a/dlls/wininet/tests/ftp.c +++ b/dlls/wininet/tests/ftp.c @@ -25,7 +25,6 @@ * TODO: * Add W-function tests. * Add missing function tests: - * FtpCommand * FtpFindFirstFile * FtpGetCurrentDirectory * FtpGetFileSize @@ -652,6 +651,46 @@ static void test_renamefile(HINTERNET hFtp, HINTERNET hConnect) "Expected ERROR_INTERNET_INCORRECT_HANDLE_TYPE, got %d\n", GetLastError()); } +static void test_command(HINTERNET hFtp, HINTERNET hConnect) +{ + BOOL ret; + DWORD error; + unsigned int i; + static const struct + { + BOOL ret; + DWORD error; + const char *cmd; + } + command_test[] = + { + { FALSE, ERROR_INVALID_PARAMETER, NULL }, + { FALSE, ERROR_INVALID_PARAMETER, "" }, + { FALSE, ERROR_INTERNET_EXTENDED_ERROR, "HELO" }, + { FALSE, ERROR_INTERNET_EXTENDED_ERROR, "SIZE " }, + { FALSE, ERROR_INTERNET_EXTENDED_ERROR, " SIZE" }, + { FALSE, ERROR_INTERNET_EXTENDED_ERROR, "SIZE " }, + { FALSE, ERROR_INTERNET_EXTENDED_ERROR, "SIZE /welcome.msg /welcome.msg" }, + { FALSE, ERROR_INTERNET_EXTENDED_ERROR, "SIZE /welcome.msg" }, + { FALSE, ERROR_INTERNET_EXTENDED_ERROR, "SIZE /welcome.msg " }, + { TRUE, ERROR_SUCCESS, "SIZE\t/welcome.msg" }, + { TRUE, ERROR_SUCCESS, "SIZE /welcome.msg" }, + { FALSE, ERROR_INTERNET_EXTENDED_ERROR, "PWD /welcome.msg" }, + { TRUE, ERROR_SUCCESS, "PWD" }, + { TRUE, ERROR_SUCCESS, "PWD\r\n" } + }; + + for (i = 0; i < sizeof(command_test) / sizeof(command_test[0]); i++) + { + SetLastError(0xdeadbeef); + ret = FtpCommandA(hFtp, FALSE, FTP_TRANSFER_TYPE_ASCII, command_test[i].cmd, 0, NULL); + error = GetLastError(); + + ok(ret == command_test[i].ret, "%d: expected FtpCommandA to %s\n", i, command_test[i].ret ? "succeed" : "fail"); + ok(error == command_test[i].error, "%d: expected error %u, got %u\n", i, command_test[i].error, error); + } +} + START_TEST(ftp) { HANDLE hInternet, hFtp, hHttp; @@ -693,6 +732,7 @@ START_TEST(ftp) test_putfile(hFtp, hHttp); test_removedir(hFtp, hHttp); test_renamefile(hFtp, hHttp); + test_command(hFtp, hHttp); InternetCloseHandle(hHttp); InternetCloseHandle(hFtp);