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.

// Note for Non-Unicode Build:
// If you get one of the following errors add comsuppw.lib (Release) or comsuppwd.lib (Debug) to the linker's "Additional Dependencies".
// Win32.obj : error LNK2019: unresolved external symbol "wchar_t * __stdcall _com_util::ConvertStringToBSTR(char const *)" 
// Win32.obj : error LNK2019: unresolved external symbol "char * __stdcall _com_util::ConvertBSTRToString(wchar_t *)"

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

using namespace std;


CComBSTR GetKey(const CString& strPassword)
{
	// TODO: Hash strPassword (e.g. MD5) and set data
	byte data[128/8];
	CComBSTR bstrKey;
	bstrKey.AppendBytes(reinterpret_cast<char*>(data), sizeof(data));
	return bstrKey;
}

// nMode: 1 = Read
//        2 = Write
sfFTPLib::IStreamFilterPtr CreateStreamFilter(const CString &strPassword, int nBits, int nMode)
{
	sfFTPLib::IStreamFilterPtr pStream;

	if(nMode == 1)
	{
		sfFTPLib::IAES128CTRReadStreamPtr pRead;
		ATLENSURE_SUCCEEDED(pRead.CreateInstance(__uuidof(sfFTPLib::AES128CTRReadStream)));

		ATLENSURE_SUCCEEDED(pRead->raw_SetKey(GetKey(strPassword)));
		pStream = pRead;
	}
	else if(nMode == 2)
	{
		sfFTPLib::IAES128CTRWriteStreamPtr pWrite;
		ATLENSURE_SUCCEEDED(pWrite.CreateInstance(__uuidof(sfFTPLib::AES128CTRWriteStream)));
		ATLENSURE_SUCCEEDED(pWrite->raw_SetKey(GetKey(strPassword)));
		pStream = pWrite;
	}

	return pStream;
}


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

	// init COM
	ATLVERIFY(SUCCEEDED(::CoInitializeEx(NULL, COINIT_MULTITHREADED)));

	try
	{
		sfFTPLib::IGlobalPtr pGlobal;
		HRESULT hr = pGlobal.CreateInstance(__uuidof(sfFTPLib::Global));
		if(SUCCEEDED(hr))
		{			
			// TODO: uncomment to load serial from string
			//pGlobal->LoadLicense(_T("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"));

			// UPnP
			sfFTPLib::IUPnPNATManagerPtr pUPnPNATManager;
			hr = pUPnPNATManager.CreateInstance(__uuidof(sfFTPLib::UPnPNATManager));
			if(SUCCEEDED(hr))
			{
				pUPnPNATManager->Initialize();
			}

			sfFTPLib::IFTPConnectionPtr ftp;
			hr = ftp.CreateInstance(__uuidof(sfFTPLib::FTPConnectionMTA));
			if(SUCCEEDED(hr))
			{
				ftp->LogFile->File = L"Win32Demo.log";

				// AUTH TLS
				ftp->_Protocol = sfFTPLib::ftpProtocolSSLExplicit;
				ftp->Host = _T("smartftp.com");
				ftp->Port = 21;
				ftp->Username = _T("anonymous");
				ftp->Password = _T("bla@bla.com");
				ftp->Passive = VARIANT_TRUE;

				// No Proxy
				//ftp->Proxy->Type = sfFTPLib::ftpProxyTypeNone;
				//ftp->Proxy->Host =_T("192.168.1.10");
				//ftp->Proxy->Port = 1080;
				//ftp->Proxy->Authentication = VARIANT_TRUE;
				//ftp->Proxy->Username = _T("user");
				//ftp->Proxy->Password = _T("pass");    

				// Connect
				ftp->Connect();
				ftp->ChangeDirectory(_T("/SmartFTP"));

				// read listing				
				sfFTPLib::IFTPItemsPtr pDirectory = ftp->ReadDirectory();
				if(pDirectory)
				{
					int nCount = pDirectory->Count;
					_tprintf(_T("Count = %d\n"), nCount);		

					// Enum
					if(nCount > 0)
					{
						IEnumVARIANTPtr pEnum = pDirectory->_NewEnum;
						ATLENSURE(pEnum);
						VARIANT *pArrVariant = new VARIANT[nCount];
						ULONG CeltFetched;
						if(SUCCEEDED(pEnum->Next(nCount, pArrVariant, &CeltFetched)))
						{
							for(ULONG i=0; i<CeltFetched; i++)
							{
								if(pArrVariant[i].vt == VT_DISPATCH)
								{
									sfFTPLib::IFTPItemPtr pFTPItem = pArrVariant[i].pdispVal;
									if(pFTPItem)
									{									
										_tprintf(_T("Type=0x%x; Name=%s; Size=%d\n"), pFTPItem->Type, (LPCTSTR)pFTPItem->Name, pFTPItem->Size);

										if(pFTPItem->Type == sfFTPLib::ftpItemTypeSymLink)
										{
											_tprintf(_T("LinkPoint=%s"), (LPCTSTR)pFTPItem->LinkPoint);
										}
									}
								}
								::VariantClear(&pArrVariant[i]);
							}
						}

						delete [] pArrVariant;
					}
				}

				// download file
				ftp->DownloadFile(_T("History.txt"), _T("History.txt"), 0, 0);
				_tprintf(_T("DownloadFile() successful.\n"));
				_tprintf(_T("LastTransferBytes = %I64u B\n"), ftp->LastTransferBytes);
				_tprintf(_T("LastTransferTime = %d s\n"), ftp->LastTransferTime);
				_tprintf(_T("LastTransferSpeed = %d B/s\n"), ftp->LastTransferSpeed);
					
				// DownloadFileEx using IStream
						
				// create a storage
				IStoragePtr pStorage;
				if(SUCCEEDED(::StgCreateDocfile(_T("Storage"), STGM_NOSCRATCH | STGM_TRANSACTED | STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, &pStorage)))
				{
					IStreamPtr pStream;
					if(SUCCEEDED(pStorage->CreateStream(L"CONTENTS", STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream)))
					{
						ftp->DownloadFileEx(_T("History.txt"), CComVariant(pStream.GetInterfacePtr()), 0, 0);
						_tprintf(_T("DownloadFileEx() successful.\n"));
					}

					pStream->Commit(STGC_OVERWRITE | STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE);
					pStorage->Commit(STGC_OVERWRITE | STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE);
				}

				// Uncomment this to test encryption. You need a server with upload permissions.
/*
						// Upload with encryption
						sfFTPLib::IStreamFilterPtr pEncryption = CreateStreamFilter(_T("Password"), 128, 1);
						ftp->StreamFilter = pEncryption;
						err = ftp->UploadFile(_T("History.txt"), _T("History.txt.encrypted"), 0, 0);

						// Download with decryption
						sfFTPLib::IStreamFilterPtr pDecryption = CreateStreamFilter(_T("Password"), 128, 2);
						ftp->StreamFilter = pDecryption;
						ftp->DownloadFile(_T("History.txt.encrypted"), _T("History.txt.decrypted"), 0, 0);
*/
			}
			else
			{
				_tprintf(_T("Failed to create CFTPConnection instance.\n"));
			}
		
			// UPnP
			if(pUPnPNATManager)
			{
				pUPnPNATManager->Uninitialize();
			}
		}
	}
	catch(_com_error &e)
	{
		_tprintf(_T("Com Error:\n"));
		_tprintf(_T("Code = %08lx\n"), e.Error());
		_tprintf(_T("Code meaning = %s\n"), (LPCTSTR) e.ErrorMessage());
		_tprintf(_T("Source = %s\n"), (LPCTSTR) e.Source());
		_tprintf(_T("Error Description = %s\n"), (LPCTSTR) e.Description());
	}
	catch(...)
	{
		_tprintf(_T("Unknown Error\n"));		
	}
	::CoUninitialize();

	return nRetCode;
}