ftp/Win32.cpp

// Win32.cpp : Defines the entry point for the console application.
//
// Summary: sfFTPLib c++ demonstration
//
// Technical support: support@smartftp.com
//
// Copyright (c) SmartSoft Ltd.

#include "stdafx.h"
#include "Win32.h"

ATL::CComSafeArray<byte> GetKey(const ATL::CString& password)
{
	// TODO: Hash strPassword (e.g. MD5) and set data
	byte data[128 / 8];

	ATL::CComSafeArray<byte> key;
	ATLENSURE_SUCCEEDED(key.Create(sizeof(data)));
	auto begin = reinterpret_cast<const byte*>(data);
	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;
}

// nMode: 1 = Read
//        2 = Write
ATL::CComPtr<sfFTPLib::IStreamFilter> CreateStreamFilter(const ATL::CString &password, int nBits, int nMode)
{
	ATL::CComPtr<sfFTPLib::IStreamFilter> pStream;

	if(nMode == 1)
	{
		ATL::CComPtr<sfFTPLib::IAES128CTRReadStream> pRead;
		ATLENSURE_SUCCEEDED(pRead.CoCreateInstance(__uuidof(sfFTPLib::AES128CTRReadStream)));

		ATLENSURE_SUCCEEDED(pRead->SetKey((byte*) password.GetString(), password.GetLength()));
		pStream = pRead;
	}
	else if (nMode == 2)
	{
		ATL::CComPtr<sfFTPLib::IAES128CTRWriteStream> pWrite;
		ATLENSURE_SUCCEEDED(pWrite.CoCreateInstance(__uuidof(sfFTPLib::AES128CTRWriteStream)));
		ATLENSURE_SUCCEEDED(pWrite->SetKey((byte*)password.GetString(), password.GetLength()));
		pStream = pWrite;
	}

	return pStream;
}

void DownloadUsingStream(_In_ sfFTPLib::IFTPConnection* connection)
{
	// create a storage
	ATL::CComPtr<IStorage> pStorage;
	ATLENSURE_SUCCEEDED(::StgCreateDocfile(_T("Storage"), STGM_NOSCRATCH | STGM_TRANSACTED | STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, &pStorage));

	ATL::CComPtr<IStream> pStream;
	ATLENSURE_SUCCEEDED(pStorage->CreateStream(L"CONTENTS", STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream));

	connection->DownloadFileEx(ATL::CComBSTR(_T("History.txt")), ATL::CComVariant(pStream.p), 0, 0, nullptr);
	_tprintf(_T("DownloadFileEx() successful.\n"));

	pStream->Commit(STGC_OVERWRITE | STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE);
	pStorage->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> pDirectory;
	ATLENSURE_SUCCEEDED(connection->ReadDirectory(&pDirectory));

	long count;
	pDirectory->get_Count(&count);
	_tprintf(_T("Count = %d\n"), count);

	// Enum
	if (count > 0)
	{
		ATL::CComPtr<IUnknown> unkEnum;
		pDirectory->get__NewEnum(&unkEnum);
		ATL::CComQIPtr<IEnumVARIANT> pEnum(unkEnum);

		auto pArrVariant = new VARIANT[count];
		ULONG CeltFetched;
		if (SUCCEEDED(pEnum->Next(count, pArrVariant, &CeltFetched)))
		{
			for (ULONG i = 0; i < CeltFetched; i++)
			{
				if (pArrVariant[i].vt == VT_DISPATCH)
				{
					ATL::CComQIPtr<sfFTPLib::IFTPItem> pFTPItem{ pArrVariant[i].pdispVal };
					
					sfFTPLib::ItemType itemType;
					ATLENSURE_SUCCEEDED(pFTPItem->get_Type(&itemType));
					ATL::CComBSTR itemName;
					ATLENSURE_SUCCEEDED(pFTPItem->get_Name(&itemName));
					ULONGLONG itemSize;
					ATLENSURE_SUCCEEDED(pFTPItem->get_Size(&itemSize));

					_tprintf(_T("Type=0x%x; Name=%s; Size=%I64u\n"), itemType, (LPCTSTR) itemName, itemSize);

					if (itemType == sfFTPLib::ftpItemTypeSymbolicLink)
					{
						ATL::CComBSTR linkPoint;
						pFTPItem->get_LinkPoint(&linkPoint);
						_tprintf(_T("LinkPoint=%s"), (LPCTSTR) linkPoint);
					}
				}
				::VariantClear(&pArrVariant[i]);
			}
		}

		delete [] pArrVariant;
	}
}

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
	int nRetCode = 0;

	// init COM
	ATLENSURE_SUCCEEDED(::CoInitializeEx(NULL, 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
	//global->LoadLicense(_T("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(_T("smartftp.com"))));
	ATLENSURE_SUCCEEDED(ftp->put_Port(21));
	ATLENSURE_SUCCEEDED(ftp->put_Username(ATL::CComBSTR(_T("anonymous"))));
	ATLENSURE_SUCCEEDED(ftp->put_Password(ATL::CComBSTR(_T("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(_T("192.168.1.10"));
	//proxy->put_Port(1080;
	//proxy->put_Authentication(VARIANT_TRUE);
	//proxy->put_Username(ATL::CComBSTR(_T("user"));
	//proxy->put_Password(ATL::CComBSTR(_T("pass"));

	ATLENSURE_SUCCEEDED(ftp->Connect());

	ReadDirectory(ftp, ATL::CComBSTR(L"/"));

	// download file
	ATLENSURE_SUCCEEDED(ftp->DownloadFile(ATL::CComBSTR(L"History.txt"), ATL::CComBSTR(L"History.txt"), 0, 0));
	_tprintf(_T("DownloadFile() successful.\n"));
	ULONGLONG lastTransferBytes;
	ATLENSURE_SUCCEEDED(ftp->get_LastTransferBytes(&lastTransferBytes));
	_tprintf(_T("LastTransferBytes = %I64u B\n"), lastTransferBytes);
	long lastTransferTime;
	ATLENSURE_SUCCEEDED(ftp->get_LastTransferTime(&lastTransferTime));
	_tprintf(_T("LastTransferTime = %d s\n"), lastTransferTime);
	long lastTransferSpeed;
	ATLENSURE_SUCCEEDED(ftp->get_LastTransferSpeed(&lastTransferSpeed));
	_tprintf(_T("LastTransferSpeed = %d B/s\n"), lastTransferSpeed);

	// DownloadFileEx using IStream
	//DownloadUsingStream(ftp);

	::CoUninitialize();

	return nRetCode;
}