Click here to Skip to main content
15,891,473 members
Articles / Desktop Programming / MFC

The Ultimate TCP/IP Home Page

Rate me:
Please Sign up or sign in to vote.
4.98/5 (77 votes)
25 Aug 2007CPOL13 min read 2.6M   45.4K   267  
Ultimate TCP-IP is now Open Source
//=================================================================
//  class: CMailServ
//  File:  MailServ.cpp
//
//  Implementation of CMailServ class
//
//=================================================================
// Ultimate TCP/IP v4.2
// This software along with its related components, documentation and files ("The Libraries")
// is � 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
// governed by a software license agreement ("Agreement").  Copies of the Agreement are
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
// to obtain this file, or directly from our office.  For a copy of the license governing
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.
//=================================================================

#include "stdafx.h"
#include "UTMailServ.h"
#include "MailServ.h"
#include "AboutDlg.h"


// Suppress warnings for non-safe str fns. Transitional, for VC6 support.
#pragma warning (push)
#pragma warning (disable : 4996)

/////////////////////////////////////////////////////////////////////////////
// CMailServ
/////////////////////////////////////////////////////////////////////////////

/***************************************************
CMailServ
	Standart constructor. 
Params
    none
Return
	none
****************************************************/
CMailServ::CMailServ() :
		m_bGoingToClose(FALSE)
{
	// Initialize server classes
	m_ptrPOP3Server = new POP3ServerEx(*this);
	m_ptrSMTPServer = new SMTPServerEx(*this);
	m_ptrSMTPOut	= new SMTPOutEx(*this);
	SetServerClasses(m_ptrPOP3Server, m_ptrSMTPServer, m_ptrSMTPOut);
	
	// Load Mail Icon
	m_hMailServIcon = LoadIcon(_Module.m_hInst, MAKEINTRESOURCE(IDI_ICON_MAILSERV));	

	// Initiate default control size 32 x 32 pixels
    SIZE	sz = { 32, 32 };
    AtlPixelToHiMetric (&sz, &m_sizeExtent);		// convert pixels to himetric
    m_sizeNatural	= m_sizeExtent;					// store natural extent

	// Disable resizing of the control
	m_bAutoSize		= TRUE;				

	// Initialize lock
	m_EventLock.Init();

	// Initialize registry root key
	_tcscpy(m_szRootKey, _T("SOFTWARE\\EMAIL_S"));
}

/***************************************************
~CMailServ
	Destructor.
Params
    none
Return
	none
****************************************************/
CMailServ::~CMailServ()
{
	m_bGoingToClose = TRUE;

	// Destroy Mail icon handle
	if(m_hMailServIcon) {
		DestroyIcon( m_hMailServIcon );							
		m_hMailServIcon = NULL;
		}

	// Terminate lock
	m_EventLock.Term();

	// Destroy server classes
	if(m_ptrPOP3Server != NULL)
		delete m_ptrPOP3Server;
	if(m_ptrSMTPServer != NULL)
		delete m_ptrSMTPServer;
	if(m_ptrSMTPOut != NULL)
		delete m_ptrSMTPOut;

}

/***************************************************
InterfaceSupportsErrorInfo
	Checks if specified interface supports error
	information.
Params
    riid	- inteface id
Return
	S_OK	- support error info
	S_FALSE - don't support error info
****************************************************/
STDMETHODIMP CMailServ::InterfaceSupportsErrorInfo(REFIID riid)
{
	static const IID* arr[] = 
	{
		&IID_IMailServ,
	};
	for (int i=0; i<sizeof(arr)/sizeof(arr[0]); i++)
	{
		if (InlineIsEqualGUID(*arr[i], riid))
			return S_OK;
	}
	return S_FALSE;
}

/***************************************************
OnDraw
	Draw the icon
Params
    di	- A reference to the ATL_DRAWINFO structure
Return
	S_OK	- success
****************************************************/
HRESULT CMailServ::OnDraw(ATL_DRAWINFO& di)
{
	// Fill background & draw a boreder
	RECT& rc = *(RECT*)di.prcBounds;
	Rectangle(di.hdcDraw, rc.left, rc.top, rc.right, rc.bottom);

	// Draw Mail Icon
	if(m_hMailServIcon)
		DrawIcon(di.hdcDraw, rc.left, rc.top, m_hMailServIcon);	
 		
	return S_OK;
}

////////////////////////////////////////////////////
//	IMailServ interface properties Set/Get functions
////////////////////////////////////////////////////

/***************************************************
get_RegistryRootKey
	Gets registry root key
Params
    pVal	- pointer to the variable receiving the value
Return
	S_OK			- success
	E_POINTER		- wrong pointer
	E_OUTOFMEMORY	- out of memory
****************************************************/
STDMETHODIMP CMailServ::get_RegistryRootKey(BSTR *pVal)
{
	if(pVal == NULL)	return E_POINTER;
	
 	if(!SysReAllocString(pVal, _bstr_t(Sys_GetRootKey())))
 		return E_OUTOFMEMORY;

	return S_OK;
}

/***************************************************
put_RegistryRootKey
	Set registry root key
Params
    newVal	- new value of the property
Return
	S_OK		- success
	S_FALSE		- can't change property now
****************************************************/
STDMETHODIMP CMailServ::put_RegistryRootKey(BSTR newVal)
{
	_bstr_t	bstrRoot = newVal;

	if(_tcsicmp(bstrRoot, Sys_GetRootKey()) == NULL)	return S_OK;

	if(FireOnRequestEdit(DISPID_REGISTRY_ROOT_KEY) == S_FALSE)
		return S_FALSE;

	Sys_SetRootKey(bstrRoot);
	
	m_bRequiresSave = TRUE;
	FireOnChanged(DISPID_REGISTRY_ROOT_KEY);
	SendOnDataChange(NULL);

	return S_OK;
}


////////////////////////////////////////////////////
//	IMailServ interface methods
////////////////////////////////////////////////////

/***************************************************
Start
	Starts finger server
Params
    Result		- pointer to the result variable
Return
	S_OK		- success
****************************************************/
STDMETHODIMP CMailServ::Start(long *Result)
{
	MarshalInterfacesToStream(this);
	*Result = CUT_MailServer::Start();
	return S_OK;
}


/***************************************************
User_Add
    Adds a new user to the user list
Params
	Name			- user name 
	Password		- user password
	MailAddresses	- email addresses separated by ','
	Result			- pointer to the result variable
Return
	S_OK			- success   
****************************************************/
STDMETHODIMP CMailServ::User_Add(BSTR Name, BSTR Password, BSTR MailAddresses, long *Result)
{
	*Result = UTE_ERROR;

	// Get pointer to the user manager class
	CUT_UserManager	*ptrUserManager = GetUserManager();

	if(ptrUserManager != NULL) {
		CUT_TStringList	listMailAddresses;
		int				index = 0;
		_TCHAR			buffer[_MAX_PATH + 1];

		while(CUT_StrMethods::ParseString(_bstr_t(MailAddresses), _T(" ,"), index++, buffer, _MAX_PATH) == UTE_SUCCESS)
			listMailAddresses.AddString(buffer);

		*Result = ptrUserManager->User_Add(_bstr_t(Name), _bstr_t(Password), listMailAddresses);
		}

	return S_OK;
}

/***************************************************
User_Modify
    Modify user in the user list
Params
	Name			    - user name to modify
    NewName			    - new user name
	NewPassword		    - new user password
	NewMailAddresses	- new email addresses separated by ','
	Result			    - pointer to the result variable
Return
	S_OK			- success   
****************************************************/
STDMETHODIMP CMailServ::User_Modify(BSTR Name, BSTR NewName, BSTR NewPassword, BSTR NewAddresses, long *Result)
{
	*Result = UTE_ERROR;

	// Get pointer to the user manager class
	CUT_UserManager	*ptrUserManager = GetUserManager();

	if(ptrUserManager != NULL) {
		CUT_TStringList	listMailAddresses;
		int				index = 0;
		_TCHAR			buffer[_MAX_PATH + 1];

		while(CUT_StrMethods::ParseString(_bstr_t(NewAddresses), _T(" ,"), index++, buffer, _MAX_PATH) == UTE_SUCCESS)
			listMailAddresses.AddString(buffer);

		*Result = ptrUserManager->User_Modify(_bstr_t(Name), _bstr_t(NewName), _bstr_t(NewPassword), &listMailAddresses);
		}

	return S_OK;
}

/***************************************************
User_Delete
    Deletes a user from the user list
Params
	Name			- user name 
	Result			- pointer to the result variable
Return
	S_OK			- success   
****************************************************/
STDMETHODIMP CMailServ::User_Delete(BSTR Name, long *Result)
{
	*Result = UTE_ERROR;

	// Get pointer to the user manager class
	CUT_UserManager	*ptrUserManager = GetUserManager();

	if(ptrUserManager != NULL) 
		*Result = ptrUserManager->User_Delete(_bstr_t(Name));

	return S_OK;
}

/***************************************************
User_GetCount
    Gets number of users in the user list
Params
	Result			- pointer to the result variable
Return
	S_OK			- success   
****************************************************/
STDMETHODIMP CMailServ::User_GetCount(long *UserCount)
{
	*UserCount = 0;

	// Get pointer to the user manager class
	CUT_UserManager	*ptrUserManager = GetUserManager();

	if(ptrUserManager != NULL) 
		*UserCount = ptrUserManager->User_GetCount();

	return S_OK;
}

/***************************************************
User_GetName
    Gets user name from the user list
Params
	Index			- index of the user
	Name			- pointer to the user name variable
Return
	S_OK			- success   
	E_OUTOFMEMORY	- out of memory
****************************************************/
STDMETHODIMP CMailServ::User_GetName(long Index, BSTR *Name)
{
	// Get pointer to the user manager class
	CUT_UserManager	*ptrUserManager = GetUserManager();

	if(ptrUserManager != NULL) {
		CUT_UserInfo *ptrUserInfo = ptrUserManager->User_GetUser(Index);
		if(ptrUserInfo != NULL) {

	 		if(!SysReAllocString(Name, _bstr_t(ptrUserInfo->szUserName)))
 				return E_OUTOFMEMORY;
			}
		}

	return S_OK;
}

/***************************************************
User_GetPassword
    Gets user password from the user list
Params
	Index			- index of the user
	Password		- pointer to the user password variable
Return
	S_OK			- success   
	E_OUTOFMEMORY	- out of memory
****************************************************/
STDMETHODIMP CMailServ::User_GetPassword(long Index, BSTR *Password)
{
	// Get pointer to the user manager class
	CUT_UserManager	*ptrUserManager = GetUserManager();

	if(ptrUserManager != NULL) {
		CUT_UserInfo *ptrUserInfo = ptrUserManager->User_GetUser(Index);
		if(ptrUserInfo != NULL) {

	 		if(!SysReAllocString(Password, _bstr_t(ptrUserInfo->szPassword)))
 				return E_OUTOFMEMORY;
			}
		}

	return S_OK;
}
/***************************************************
User_GetAddress
    Gets user address from the user list
Params
	Index			- index of the user
	MailAddresses	- pointer to the email addresses separated by ',' variable
Return
	S_OK			- success   
	E_OUTOFMEMORY	- out of memory
****************************************************/
STDMETHODIMP CMailServ::User_GetAddress(long Index, BSTR *MailAddresses)
{
	// Get pointer to the user manager class
	CUT_UserManager	*ptrUserManager = GetUserManager();

	if(ptrUserManager != NULL) {
		CUT_UserInfo *ptrUserInfo = ptrUserManager->User_GetUser(Index);
		if(ptrUserInfo != NULL) {

			// Convert list of email addresses to one string separated with ','
			_bstr_t	bstrMailAddresses = "";
			for(int i=0; i<ptrUserInfo->listEmailAddresses.GetCount(); i++){
				if(i != 0)
					bstrMailAddresses += ",";
				bstrMailAddresses += ptrUserInfo->listEmailAddresses.GetString(i);
				}

	 		if(!SysReAllocString(MailAddresses, bstrMailAddresses))
 				return E_OUTOFMEMORY;
			}
		}

	return S_OK;
}

/***************************************************
DNS_GetCount
    Gets number of DNS names 
Params
	DNSCount	- pointer to the result variable
Return
	S_OK		- success   
****************************************************/
STDMETHODIMP CMailServ::DNS_GetCount(long *DNSCount)
{
	*DNSCount = Sys_GetDNSNamesCount();
	return S_OK;
}

/***************************************************
DNS_Get
    Gets DNS name by index
Params
	Index	- index of DNS name to get	
	DNSName	- pointer to the result variable
Return
	S_OK			- success   
	E_OUTOFMEMORY	- out of memory
****************************************************/
STDMETHODIMP CMailServ::DNS_Get(long Index, BSTR *DNSName)
{
	if(!SysReAllocString(DNSName, _bstr_t(Sys_GetDNSName(Index))))
		return E_OUTOFMEMORY;
	return S_OK;
}

/***************************************************
DNS_Add
    Adds new DNS name to the list
Params
	DNSName	- DNS name to add
	Result	- pointer to the result variable
Return
	S_OK	- success   
****************************************************/
STDMETHODIMP CMailServ::DNS_Add(BSTR DNSName, long *Result)
{
	*Result = UTE_ERROR;
	if(Sys_AddDNSName(_bstr_t(DNSName)))
		*Result = UTE_SUCCESS;	
	return S_OK;
}

/***************************************************
DNS_Delete
    Deletes a DNS name from the list
Params
	Index	- index of DNS name to delete
	Result	- pointer to the result variable
Return
	S_OK	- success   
****************************************************/
STDMETHODIMP CMailServ::DNS_Delete(long Index, long *Result)
{
	*Result = UTE_ERROR;
	if(Sys_DeleteDNSName(Index))
		*Result = UTE_SUCCESS;	
	return S_OK;
}

/***************************************************
LocalName_GetCount
    Gets number of Local Names names 
Params
	LocalNamesCount	- pointer to the result variable
Return
	S_OK			- success   
****************************************************/
STDMETHODIMP CMailServ::LocalName_GetCount(long *LocalNamesCount)
{
	*LocalNamesCount = Sys_GetLocalNamesCount();
	return S_OK;
}

/***************************************************
LocalName_Get
    Gets Local Name by index
Params
	Index		- index of DNS name to get	
	LocalName	- pointer to the result variable
Return
	S_OK			- success   
	E_OUTOFMEMORY	- out of memory
****************************************************/
STDMETHODIMP CMailServ::LocalName_Get(long Index, BSTR *LocalName)
{
	if(!SysReAllocString(LocalName, _bstr_t(Sys_GetLocalName(Index))))
		return E_OUTOFMEMORY;
	return S_OK;
}

/***************************************************
LocalName_Add
    Adds new Local Name to the list
Params
	LocalName	- Local Name to add
	Result		- pointer to the result variable
Return
	S_OK	- success   
****************************************************/
STDMETHODIMP CMailServ::LocalName_Add(BSTR LocalName, long *Result)
{
	*Result = UTE_ERROR;
	if(Sys_AddLocalName(_bstr_t(LocalName)))
		*Result = UTE_SUCCESS;	

	return S_OK;
}

/***************************************************
LocalName_Delete
    Deletes a Local Name from the list
Params
	Index	- index of DNS name to delete
	Result	- pointer to the result variable
Return
	S_OK	- success   
****************************************************/
STDMETHODIMP CMailServ::LocalName_Delete(long Index, long *Result)
{
	*Result = UTE_ERROR;
	if(Sys_DeleteLocalName(Index))
		*Result = UTE_SUCCESS;	

	return S_OK;
}

/***************************************************
AboutBox
	Display about box
Params
    none
Return
	S_OK		- success
****************************************************/
STDMETHODIMP CMailServ::AboutBox()
{
	CAboutDlg	dlg;

	dlg.DoModal();
	return S_OK;
}

/***************************************************
GetErrorText
	Returns a string representation of numeric error code.
Params
	ErrorCode	- number of error code
	ErrorText	- pointer to the error text varaible
Return
	S_OK			- success
	E_OUTOFMEMORY	- out of memory
****************************************************/
STDMETHODIMP CMailServ::GetErrorText(long ErrorCode, BSTR *ErrorText)
{
 	HRESULT		hResult			= S_OK;
 	CComBSTR	bstrErrorMsg	= CUT_ERR::GetErrorString(ErrorCode);
 
 	if(!SysReAllocString(ErrorText, bstrErrorMsg))
 		hResult = E_OUTOFMEMORY;
 
 	return hResult;
}

/***************************************************
GetInterfaceSafetyOptions
	Gets inteface safety options
Params
	riid				- interface ID
	pdwSupportedOptions	- supported options
	pdwEnabledOptions	- enabled options
Return
	S_OK			- success
	E_NOINTERFACE	- no such interface
	E_FAIL			- failed
****************************************************/
STDMETHODIMP CMailServ::GetInterfaceSafetyOptions(REFIID riid, DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions)
{

	ATLTRACE(_T("CObjectSafetyImpl::GetInterfaceSafetyOptions\n"));

	if (!pdwSupportedOptions || !pdwEnabledOptions)
		return E_FAIL;

	LPUNKNOWN pUnk;
	if (_InternalQueryInterface (riid, (void**)&pUnk) == E_NOINTERFACE) {
		// Our object doesn't even support this interface.
		return E_NOINTERFACE;
		}
	else {
		// Cleanup after ourselves.
		pUnk->Release();
		pUnk = NULL;
		}

	if (riid == IID_IDispatch) {
		// IDispatch is an interface used for scripting. If your
		// control supports other IDispatch or Dual interfaces, you
		// may decide to add them here as well. Client wants to know
		// if object is safe for scripting. Only indicate safe for
		// scripting when the interface is safe.
		*pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
		*pdwEnabledOptions = m_dwCurrentSafety & INTERFACESAFE_FOR_UNTRUSTED_CALLER;
		return S_OK;
		}
	else if ((riid == IID_IPersistStreamInit) || (riid == IID_IPersistStorage) || (riid == IID_IPersistPropertyBag)) {
		// IID_IPersistStreamInit and IID_IPersistStorage are
		// interfaces used for Initialization. If your control
		// supports other Persistence interfaces, you may decide to
		// add them here as well. Client wants to know if object is
		// safe for initializing. Only indicate safe for initializing
		// when the interface is safe.
		*pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA;
		*pdwEnabledOptions = m_dwCurrentSafety & INTERFACESAFE_FOR_UNTRUSTED_DATA;
		return S_OK;
		}
	else {
		// We are saying that no other interfaces in this control are
		// safe for initializing or scripting.
		*pdwSupportedOptions = 0;
		*pdwEnabledOptions = 0;
		return E_FAIL;
		}
   }


/***************************************************
SetInterfaceSafetyOptions
	Sets inteface safety options
Params
	riid				- interface ID
	dwOptionSetMask		- options mask
	pdwEnabledOptions	- enabled options
Return
	S_OK			- success
	E_NOINTERFACE	- no such interface
	E_FAIL			- failed
****************************************************/
STDMETHODIMP CMailServ::SetInterfaceSafetyOptions(REFIID riid, DWORD dwOptionSetMask, DWORD dwEnabledOptions)
{

	ATLTRACE(_T("CObjectSafetyImpl::SetInterfaceSafetyOptions\n"));

	if (!dwOptionSetMask && !dwEnabledOptions) return E_FAIL;
   
	LPUNKNOWN pUnk;
	if (_InternalQueryInterface (riid, (void**)&pUnk) == E_NOINTERFACE) {
		// Our object doesn't even support this interface.
		return E_NOINTERFACE;
		}
	else {
		// Cleanup after ourselves.
		pUnk->Release();
		pUnk = NULL;
		}

	// Store our current safety level to return in
	// GetInterfaceSafetyOptions
	m_dwCurrentSafety |= dwEnabledOptions & dwOptionSetMask;
	if ((riid == IID_IDispatch) && (m_dwCurrentSafety & INTERFACESAFE_FOR_UNTRUSTED_CALLER)) {
		// Client wants us to disable any functionality that would
		// make the control unsafe for scripting. The same applies to
		// any other IDispatch or Dual interfaces your control may
		// support. Because our control is safe for scripting by
		// default we just return S_OK.
		return S_OK;
		}
	else if (((riid == IID_IPersistStreamInit) || (riid == IID_IPersistStorage) || (riid == IID_IPersistPropertyBag)) &&
             (m_dwCurrentSafety & INTERFACESAFE_FOR_UNTRUSTED_DATA)) {
		// Client wants us to make the control safe for initializing
		// from persistent data. For these interfaces, this control
		// is safe so we return S_OK. For Any interfaces that are not
		// safe, we would return E_FAIL.
		return S_OK;
		}
	else {
		// This control doesn't allow Initialization or Scripting
		// from any other interfaces so return E_FAIL.
		return E_FAIL;
		}
}

/***************************************************
OnStatus
    This virtual function is called each time we have any
	status information to display.
Params
	StatusText	- status text
Return
	UTE_SUCCESS - success   
****************************************************/
int CMailServ::OnStatus(LPCSTR StatusText)
{
	if(!m_bGoingToClose) {
		m_EventLock.Lock();
		Fire_OnStatus(_bstr_t(StatusText));
		m_EventLock.Unlock();
		}
	return UTE_SUCCESS;
}
/***************************************************
OnCanAccept
    This virtual function is called each time the server 
    accepting new connection.
Params
	LPCSTR	    - IP address of connecting user
Return
	TRUE        - accept 
    FALSE       - cancel
****************************************************/
long CMailServ::OnCanAccept(LPCSTR address){
    VARIANT_BOOL	result	= TRUE;
	if(!m_bGoingToClose) {
    	HRESULT	hr = CoInitialize(NULL);

		m_EventLock.Lock();
		Fire_OnCanAccept(_bstr_t(address), &result);
		m_EventLock.Unlock();

    	if(hr == S_OK)
	    		CoUninitialize();					
		}
    return (long)result;
}

/////////////////////////////////////////////////////////////////////////////
// POP3ServerEx
/////////////////////////////////////////////////////////////////////////////

/********************************
CreateInstance
    Creates an Instance of a
    CUT_POP3Thread class and return
    a pointer to it
Params
    none
Return
    pointer to an instance of a 
    CUT_POP3Thread
*********************************/
CUT_WSThread * POP3ServerEx::CreateInstance(){
   return new POP3ThreadEx;
}


/////////////////////////////////////////////////////////////////////////////
// POP3ThreadEx
/////////////////////////////////////////////////////////////////////////////

/********************************
OnMaxConnect
    This function is called when a
    new connection is made and the
    system has already reached its
    max. number of allowed connections
Params
    none
Return 
    none
*********************************/
void POP3ThreadEx::OnMaxConnect(){
	HRESULT	hr = CoInitialize(NULL);

	CUT_POP3Thread::OnMaxConnect();

	if(hr == S_OK)
			CoUninitialize();					
}

/********************************
OnConnect
    This function is called when a new 
    connection is made. This function
    receives all of the POP3 commands
    and processes them
Params
    none
Return
    none
*********************************/
void POP3ThreadEx::OnConnect(){
	HRESULT	hr = CoInitialize(NULL);

	CUT_POP3Thread::OnConnect();

	if(hr == S_OK)
			CoUninitialize();					
}

/////////////////////////////////////////////////////////////////////////////
// SMTPServerEx
/////////////////////////////////////////////////////////////////////////////

/********************************
CreateInstance
    Creates an Instance of a
    CUT_POP3Thread class and return
    a pointer to it
Params
    none
Return
    pointer to an instance of a 
    CUT_POP3Thread
*********************************/
CUT_WSThread * SMTPServerEx::CreateInstance(){
   return new SMTPThreadEx;
}

/////////////////////////////////////////////////////////////////////////////
// SMTPThreadEx
/////////////////////////////////////////////////////////////////////////////

/********************************
OnMaxConnect
    This function is called when a
    new connection is made and the
    system has already reached its
    max. number of allowed connections
Params
    none
Return 
    none
*********************************/
void SMTPThreadEx::OnMaxConnect(){
	HRESULT	hr = CoInitialize(NULL);

	CUT_SMTPThread::OnMaxConnect();

	if(hr == S_OK)
			CoUninitialize();					
}

/********************************
OnConnect
    This function is called when a new 
    connection is made. This function
    receives all of the POP3 commands
    and processes them
Params
    none
Return
    none
*********************************/
void SMTPThreadEx::OnConnect(){
	HRESULT	hr = CoInitialize(NULL);

	CUT_SMTPThread::OnConnect();

	if(hr == S_OK)
			CoUninitialize();					
}

/////////////////////////////////////////////////////////////////////////////
// SMTPOutEx
/////////////////////////////////////////////////////////////////////////////
/***************************************
SendMail
    Sends mail
Params
    info - pointer to the calling CUT_SMTPOut class        
Return
    none
****************************************/
void SMTPOutEx::SendMail(CUT_SMTPOutInfo	*info)
{
	HRESULT	hr = CoInitialize(NULL);

	CUT_SMTPOut::SendMail(info);

	if(hr == S_OK)
			CoUninitialize();					
}


#pragma warning (pop)

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Canada Canada
In January 2005, David Cunningham and Chris Maunder created TheUltimateToolbox.com, a new group dedicated to the continued development, support and growth of Dundas Software’s award winning line of MFC, C++ and ActiveX control products.

Ultimate Grid for MFC, Ultimate Toolbox for MFC, and Ultimate TCP/IP have been stalwarts of C++/MFC development for a decade. Thousands of developers have used these products to speed their time to market, improve the quality of their finished products, and enhance the reliability and flexibility of their software.
This is a Organisation

476 members

Comments and Discussions