ftp/Win32.cpp
// Win32.cpp : Defines the entry point for the console application.
//
// Summary: sfFTPLib c++ demonstration
//
// Technical support: support@smartftp.com
#include "stdafx.h"
#include "Win32.h"
#include <string_view>
#include <memory>
[[nodiscard]] ATL::CComSafeArray<byte> GetKey(const std::wstring_view password)
{
// TODO: Hash password (e.g. SHA1) and set data
byte data[128 / 8]{};
ATL::CComSafeArray<byte> key;
ATLENSURE_SUCCEEDED(key.Create(sizeof(data)));
const auto begin{ reinterpret_cast<const byte*>(data) };
const auto end{ reinterpret_cast<const byte*>(data) + sizeof(data) };
auto it{ begin };
for (long Index = 0; it != end; Index++, ++it)
{
key.SetAt(Index, *it);
}
return key;
}
// mode: 1 = Read, 2 = Write
[[nodiscard]] ATL::CComPtr<sfFTPLib::IStreamFilter> CreateStreamFilter(const std::wstring_view password, int nBits, int mode)
{
ATL::CComPtr<sfFTPLib::IStreamFilter> stream;
if (mode == 1)
{
ATL::CComPtr<sfFTPLib::IAES128CTRReadStream> readStream;
ATLENSURE_SUCCEEDED(readStream.CoCreateInstance(__uuidof(sfFTPLib::AES128CTRReadStream)));
ATLENSURE_SUCCEEDED(readStream->SetKey(const_cast<byte*>(reinterpret_cast<const byte*>(password.data())), password.size()));
stream = readStream;
}
else if (mode == 2)
{
ATL::CComPtr<sfFTPLib::IAES128CTRWriteStream> writeStream;
ATLENSURE_SUCCEEDED(writeStream.CoCreateInstance(__uuidof(sfFTPLib::AES128CTRWriteStream)));
ATLENSURE_SUCCEEDED(writeStream->SetKey(const_cast<byte*>(reinterpret_cast<const byte*>(password.data())), password.size()));
stream = writeStream;
}
return stream;
}
void DownloadUsingStream(_In_ sfFTPLib::IFTPConnection* connection)
{
// create a storage
ATL::CComPtr<IStorage> storage;
ATLENSURE_SUCCEEDED(::StgCreateDocfile(L"Storage", STGM_NOSCRATCH | STGM_TRANSACTED | STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, &storage));
ATL::CComPtr<IStream> stream;
ATLENSURE_SUCCEEDED(storage->CreateStream(L"CONTENTS", STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stream));
ATLENSURE_SUCCEEDED(connection->DownloadFileEx(ATL::CComBSTR(L"This is a DEMO server.txt"), ATL::CComVariant(stream.p), 0, MAXULONGLONG, nullptr));
::wprintf(L"DownloadFileEx() successful.\n");
stream->Commit(STGC_OVERWRITE | STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE);
storage->Commit(STGC_OVERWRITE | STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE);
}
void ReadDirectory(_In_ sfFTPLib::IFTPConnection* connection, _In_z_ PCWSTR directory)
{
ATLENSURE_SUCCEEDED(connection->ChangeDirectory(ATL::CComBSTR(directory)));
// read listing
ATL::CComPtr<sfFTPLib::IFTPItems> directoryItems;
ATLENSURE_SUCCEEDED(connection->ReadDirectory(&directoryItems));
long count;
ATLENSURE_SUCCEEDED(directoryItems->get_Count(&count));
::wprintf(L"Count = %d\n", count);
// Enum
if (count > 0)
{
ATL::CComPtr<IUnknown> unkEnum;
directoryItems->get__NewEnum(&unkEnum);
ATL::CComQIPtr<IEnumVARIANT> pEnum(unkEnum);
const auto pArrVariant{ std::make_unique<VARIANT[]>(count) };
ULONG fetched;
if (SUCCEEDED(pEnum->Next(count, pArrVariant.get(), &fetched)))
{
for (ULONG i = 0; i < fetched; i++)
{
if (pArrVariant[i].vt == VT_DISPATCH)
{
ATL::CComQIPtr<sfFTPLib::IFTPItem> item{ pArrVariant[i].pdispVal };
sfFTPLib::ItemType itemType;
ATLENSURE_SUCCEEDED(item->get_Type(&itemType));
ATL::CComBSTR itemName;
ATLENSURE_SUCCEEDED(item->get_Name(&itemName));
ULONGLONG itemSize;
ATLENSURE_SUCCEEDED(item->get_Size(&itemSize));
::wprintf(L"Type=0x%x; Name=%s; Size=%I64u\n", itemType, (PCWSTR) itemName, itemSize);
if (itemType == sfFTPLib::ftpItemTypeSymbolicLink)
{
ATL::CComBSTR linkPoint;
item->get_LinkPoint(&linkPoint);
::wprintf(L"LinkPoint=%s", (PCWSTR) linkPoint);
}
}
::VariantClear(&pArrVariant[i]);
}
}
}
}
int wmain(int argc, wchar_t* argv[], wchar_t* envp[])
{
ATLENSURE_SUCCEEDED(::CoInitializeEx(nullptr, COINIT_MULTITHREADED));
ATL::CComPtr<sfFTPLib::IGlobal> global;
ATLENSURE_SUCCEEDED(global.CoCreateInstance(__uuidof(sfFTPLib::Global)));
// If LoadLicense is not called a trial license is automatically obtained from the activation server. The FTP Library uses WinHTTP to access
// the activation server at www.smartftp.com (TLS, port 443). Ensure that your application is not blocked by any firewall.
// TODO: insert the provided serial after the purchase of a license
//ATLENSURE_SUCCEEDED(global->LoadLicense(ATL::CComBSTR(L"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX")));
ATL::CComPtr<sfFTPLib::IFTPConnection> ftp;
ATLENSURE_SUCCEEDED(ftp.CoCreateInstance(__uuidof(sfFTPLib::FTPConnectionMTA)));
ATL::CComPtr<sfFTPLib::IFileLogger> fileLogger;
ATLENSURE_SUCCEEDED(fileLogger.CoCreateInstance(__uuidof(sfFTPLib::FileLogger)));
ATLENSURE_SUCCEEDED(fileLogger->put_File(ATL::CComBSTR(L"Win32Demo.log")));
ATL::CComQIPtr<sfFTPLib::ILogger> logger{ fileLogger };
ATLENSURE_SUCCEEDED(ftp->put_Logger(logger));
// AUTH TLS
ATLENSURE_SUCCEEDED(ftp->put_Protocol(sfFTPLib::ftpProtocolSSLExplicit));
ATLENSURE_SUCCEEDED(ftp->put_Host(ATL::CComBSTR(L"smartftp.com")));
ATLENSURE_SUCCEEDED(ftp->put_Port(21));
ATLENSURE_SUCCEEDED(ftp->put_Username(ATL::CComBSTR(L"anonymous")));
ATLENSURE_SUCCEEDED(ftp->put_Password(ATL::CComBSTR(L"bla@bla.com")));
ATLENSURE_SUCCEEDED(ftp->put_Passive(VARIANT_TRUE));
// No Proxy
// ATL::CComPtr<IProxy> proxy;
// ATLENSURE_SUCCEEDED(ftp->get_Proxy(&proxy));
//proxy->put_Type(sfFTPLib::ftpProxyTypeNone);
//proxy->put_Host(ATL::CComBSTR(L"192.168.1.10");
//proxy->put_Port(1080;
//proxy->put_Authentication(VARIANT_TRUE);
//proxy->put_Username(ATL::CComBSTR(L"user");
//proxy->put_Password(ATL::CComBSTR(L"pass");
ATLENSURE_SUCCEEDED(ftp->Connect());
ReadDirectory(ftp, ATL::CComBSTR(L"/"));
// download file
ATLENSURE_SUCCEEDED(ftp->DownloadFileEx(ATL::CComBSTR(L"This is a DEMO server.txt"), ATL::CComVariant(L"This is a DEMO server.txt"), 0, MAXULONGLONG, nullptr));
::wprintf(L"DownloadFile() successful.\n");
ULONGLONG lastTransferBytes;
ATLENSURE_SUCCEEDED(ftp->get_LastTransferBytes(&lastTransferBytes));
::wprintf(L"LastTransferBytes = %I64u B\n", lastTransferBytes);
long lastTransferTime;
ATLENSURE_SUCCEEDED(ftp->get_LastTransferTime(&lastTransferTime));
::wprintf(L"LastTransferTime = %d s\n", lastTransferTime);
long lastTransferSpeed;
ATLENSURE_SUCCEEDED(ftp->get_LastTransferSpeed(&lastTransferSpeed));
::wprintf(L"LastTransferSpeed = %d B/s\n", lastTransferSpeed);
// DownloadFileEx using IStream
//DownloadUsingStream(ftp);
// Upload file
//ATLENSURE_SUCCEEDED(ftp->UploadFileEx(ATL::CComVariant(L"c:\\test.dat"), ATL::CComBSTR(L"test.dat"), 0, nullptr));
::CoUninitialize();
return 0;
}