//  Beta release only.
//
//  Copyright(c) Ivyware Pty Ltd 2013  (all rights reserved)
//               MELBOURNE, VICTORIA, AUSTRALIA, 3130
//
//  Provided no fee is charged (either by the distributer or user)
//  permission to use, copy, modify, and distribute this software and
//  its documentation for any purpose and without fee is hereby granted,
//  provided that the above copyright notice appear in all copies and
//  that both that copyright notice and this permission notice appear
//  in supporting documentation.
//
//  No waranty or suitablity for purpose is implied.
//
//
//  IMessage environment wrapper class implementation
//  NOTES: Manages all subordinate IMessage resources
//      

#include "stdafx.h"
#include "MAPIEx.h"
#include "MAPI_Ext.h"
#include "P2Pevent.h"

/////////////////////////////////////////////////////////////
//  CMAPImessage

CMAPImessage::CMAPImessage()
{
    m_pRecipients   = nullptr;
    m_pCMAPISession = nullptr;
}

CMAPImessage::~CMAPImessage()
{
    Close ( );
}

///////////////////////////////////////////////
//  Internal Operations

void
CMAPImessage::SetMessageFlags ( int nFlags )
{
    SPropValue prop;
    prop.ulPropTag=PR_MESSAGE_FLAGS;
    prop.Value.l=nFlags;
    HRESULT hr = m_pIMAPIProp -> SetProps ( 1, &prop, NULL);
    if ( hr != S_OK )
      THROW_MAPI ( hr, "IMAPIProp::SetProps() failed" );
    return;
}

int
CMAPImessage::GetMessageFlags ( )
{
    return GetPropertyValue ( PR_MESSAGE_FLAGS, 0 );
}

void
CMAPImessage::GetMessageClass ( CString& strMessageClass )
{
    if ( GetPropertyString(PR_MESSAGE_CLASS,strMessageClass) != S_OK )
      ThrowP2Pevent ( );
    return;
}

BOOL
CMAPImessage::Create ( CMAPISession* pCMAPISession, BOOL bSaveToSentFolder, CMAPIFolder* pFolder)
{
    // To be sure, to be sure
    HRESULT hr = S_OK;
    if ( m_pIMAPIProp )
      THROW_MAPI ( 0, "Message already created" );
    m_pCMAPISession = pCMAPISession;

    // Create and lock in message
    hr = pFolder->GetIMAPIFolder()->CreateMessage(NULL, 0, (LPMESSAGE*)&m_pIMAPIProp);
    if ( hr != S_OK )
      return MAPI_HRESULT ( hr, "IMAPIFolder::CreateMessage() failed");
    LPSPropValue pProp;
    hr = GetProperty ( PR_ENTRYID, pProp );
    if ( hr != S_OK )
      return hr;
    P2PsafeMAPIbuffer PropValueSB = pProp;       // Lock in resource recovery regardless
    SetSBinEntryID ( &pProp->Value.bin );

    // Message initialisation
    SPropValue oProp;
    SetMessageFlags ( MSGFLAG_UNSENT | MSGFLAG_FROMME );

    ULONG cValues  = 0;
    ULONG rgTags[] = { 1, PR_IPM_SENTMAIL_ENTRYID };

    hr = pCMAPISession->GetMsgStore()->GetIMsgStore()->GetProps((LPSPropTagArray) rgTags, T_MAPI_UNICODE, &cValues, &pProp);
    if ( hr != S_OK )
      THROW_MAPI ( hr, "IMsgStore::GetProps() failed" );
    if ( bSaveToSentFolder)
    {
      oProp.ulPropTag=PR_SENTMAIL_ENTRYID;
      oProp.Value.bin=pProp[0].Value.bin;
    }
    else
    {
      oProp.ulPropTag=PR_DELETE_AFTER_SUBMIT;
      oProp.Value.b=TRUE;
    }
    GetIMessage()->SetProps(1, &oProp, NULL);
    SetSBinEntryID(&(pProp[0].Value.bin));

    return TRUE;
}

void
CMAPImessage::Close ( )
{
    RELEASE(m_pRecipients);
    m_pCMAPISession = nullptr;
	  CMAPIProp::Close ( );
}

//
//  Mimics Outlook {Send} button
//  NOTES: Assumes message previously constructed via SetSubject(),
//         SetSender(), SetAttachment() etc
HRESULT
CMAPImessage::SubmitMessage ( ULONG ulFlags )
{
    HRESULT   hr        = S_OK;
    IMessage *pIMessage = GetIMessage ( ); // Open() prerequisite
    if ( pIMessage == nullptr )
      return MAPI_HRESULT(MAPI_E_NOT_INITIALIZED,"IMessage==nullptr");
    if ( (GetMessageFlags()&MSGFLAG_UNSENT) != MSGFLAG_UNSENT )
      return MAPI_HRESULT(0,"Submit message requires MSGFLAG_UNSENT flag to be set");
    hr = pIMessage -> SubmitMessage ( ulFlags );
    if ( hr != S_OK )
	    return MAPI_HRESULT(hr,"IMessage::SubmitMessage() failed");
		Close();
    return hr;
}

///////////////////////////////////////////////////////////////////////////////
//  Message property assignment

BOOL
CMAPImessage::AddRecipients(LPADRLIST pAddressList)
{
    HRESULT hr=E_INVALIDARG;
    LPADRBOOK pAddressBook;
    if(m_pCMAPISession->GetIMAPISession()->OpenAddressBook(0, NULL, AB_NO_DIALOG, &pAddressBook)!=S_OK) return FALSE;

    if(pAddressBook->ResolveName(0, T_MAPI_UNICODE, NULL, pAddressList)==S_OK) hr=GetIMessage()->ModifyRecipients(MODRECIP_ADD, pAddressList);
      RELEASE(pAddressBook);
    return (hr==S_OK);
}

BOOL
CMAPImessage::AddRecipient ( LPCTSTR lpszEmail, int nType, LPCTSTR szAddrType )
{
	if(!GetIMessage() || !m_pCMAPISession) return FALSE;

    // Recipient buffer allocation
	  ULONG     cbSize        = CbNewADRLIST(1);
	  LPADRLIST  pAddressList = nullptr;
	  SCODE sc = MAPIAllocateBuffer ( cbSize, (LPVOID FAR*)&pAddressList);
    if ( sc != S_OK )
      EVERR_MAPI(sc,"MAPIAllocateBuffer() failed")->Throw();
    P2PsafeMAPIbuffer sbAddressList = pAddressList;
	  memset ( pAddressList, 0, cbSize );

	int nProperties=3;
	if(szAddrType==NULL) nProperties--;
	pAddressList->cEntries=1;

	pAddressList->aEntries[0].ulReserved1=0;
	pAddressList->aEntries[0].cValues=nProperties;

	MAPIAllocateBuffer(sizeof(SPropValue)*nProperties, (LPVOID FAR*)&pAddressList->aEntries[0].rgPropVals);
	memset(pAddressList->aEntries[0].rgPropVals, 0, sizeof(SPropValue)*nProperties);

	pAddressList->aEntries[0].rgPropVals[0].ulPropTag=PR_RECIPIENT_TYPE;
	pAddressList->aEntries[0].rgPropVals[0].Value.ul=nType;

	pAddressList->aEntries[0].rgPropVals[1].ulPropTag=PR_DISPLAY_NAME;
	pAddressList->aEntries[0].rgPropVals[1].Value.LPSZ=(TCHAR*)lpszEmail;

	if(szAddrType!=NULL) 
	{
		pAddressList->aEntries[0].rgPropVals[2].ulPropTag=PR_ADDRTYPE;
		pAddressList->aEntries[0].rgPropVals[2].Value.LPSZ=(TCHAR*)szAddrType;
	}

	BOOL bResult=AddRecipients(pAddressList);
	FreePadrlist(pAddressList);
	return bResult;
}

void
CMAPImessage::SetSender(LPCTSTR szSenderName, LPCTSTR szSenderEmail)
{
	m_strSenderName=szSenderName;
	m_strSenderEmail=szSenderEmail;
	LPTSTR szAddrType=_T("SMTP");
	if(m_strSenderName.GetLength() && m_strSenderEmail.GetLength()) 
	{
		SetPropertyString(PR_SENDER_NAME, szSenderName);
		SetPropertyString(PR_SENDER_EMAIL_ADDRESS, szSenderEmail);

		LPADRBOOK pAddressBook;
		if(m_pCMAPISession->GetIMAPISession()->OpenAddressBook(0, NULL, AB_NO_DIALOG, &pAddressBook)==S_OK) 
		{
			SPropValue prop;
			if(pAddressBook->CreateOneOff((LPTSTR)szSenderName, szAddrType, (LPTSTR)szSenderEmail, 0, &prop.Value.bin.cb, (LPENTRYID*)&prop.Value.bin.lpb)==S_OK)
			{
				prop.ulPropTag=PR_SENT_REPRESENTING_ENTRYID;
				GetIMessage()->SetProps(1, &prop, NULL);

				SetPropertyString(PR_SENT_REPRESENTING_NAME, szSenderName);
				SetPropertyString(PR_SENT_REPRESENTING_EMAIL_ADDRESS, szSenderEmail);
				SetPropertyString(PR_SENT_REPRESENTING_ADDRTYPE, szAddrType);
			}
		}
		RELEASE(pAddressBook);
	}
}

//
//  Request read receipt sent to nominated email address
//
//  Parameters:  bSet
//
//               lpszReceiverEmail
//
//  Returns:     HRESULT
HRESULT
CMAPImessage::SetReadReceipt ( BOOL bSet, LPCTSTR lpszReceiverEmail )
{
    HRESULT    hr;
    SPropValue prop;
    prop.ulPropTag = PR_READ_RECEIPT_REQUESTED;
    prop.Value.b   = (unsigned short)bSet;
    hr = GetIMessage() -> SetProps ( 1, &prop, NULL );
    if ( hr != S_OK )
      return MAPI_HRESULT ( hr, "IMessage::SetProps() failed" );
    if (   bSet &&
           lpszReceiverEmail &&
          _tcslen(lpszReceiverEmail) > 0 )
      hr = SetPropertyString ( PR_READ_RECEIPT_REQUESTED, lpszReceiverEmail );
    return hr;
}

//
//  Switches delievery receipt on or off
HRESULT
CMAPImessage::SetDeliveryReport ( BOOL bReport )
{
    HRESULT    hr;
    SPropValue prop;
    prop.ulPropTag = PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED;
    prop.Value.b   = (unsigned short)bReport;
    hr = GetIMessage() -> SetProps ( 1, &prop, NULL );
    if ( hr != S_OK )
      MAPI_HRESULT ( hr, "IMessage::SetProps(PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED) failed" );
    return hr;
}

HRESULT
CMAPImessage::SetSensitivity ( int nSensitivity )
{
    HRESULT hr;
    SPropValue prop;
    prop.ulPropTag = PR_SENSITIVITY;
    prop.Value.l   = nSensitivity;
    hr = GetIMessage() -> SetProps ( 1, &prop, NULL );
    if ( hr != S_OK )
      MAPI_HRESULT ( hr, "IMessage::SetProps() failed" );
    return hr;
}

HRESULT
CMAPImessage::SetMessageStatus ( int nMessageStatus )
{
    HRESULT    hr;
    SPropValue prop;
    prop.ulPropTag = PR_MSG_STATUS;
    prop.Value.ul  = nMessageStatus;
    hr = GetIMessage() -> SetProps ( 1, &prop, NULL );
    if ( hr != S_OK )
      MAPI_HRESULT ( hr, "IMessage::SetProps() failed" );
    return hr;
}

HRESULT
CMAPImessage::SetImportance ( int nPriority )
{
    SPropValue oProp;
    oProp.ulPropTag=PR_IMPORTANCE;
    if ( nPriority == IMPORTANCE_LOW    ||
         nPriority == IMPORTANCE_NORMAL ||
         nPriority == IMPORTANCE_HIGH      )
      oProp.Value.l = nPriority;
    else
      oProp.Value.l = IMPORTANCE_NORMAL;
    HRESULT hr = GetIMessage() -> SetProps(1, &oProp, NULL);
    if ( hr != S_OK )
      MAPI_HRESULT ( hr, "IMessage::SetProps() failed" );
    return hr;
}

///////////////////////////////////////////////////////////////////////////////
//  Message subject and body management

void
CMAPImessage::SetSubject ( LPCTSTR lpszSubject )
{
	  m_strSubject = lpszSubject;
    SetPropertyString ( PR_SUBJECT, lpszSubject );
}

HRESULT
CMAPImessage::SetMessageEditorFormat ( int nFormat )
{
    SPropValue prop;
    prop.ulPropTag = PR_MSG_EDITOR_FORMAT;
    prop.Value.l   = nFormat;
    return m_pIMAPIProp -> SetProps ( 1, &prop, NULL );
}

BOOL
CMAPImessage::SetBody ( LPCTSTR lpszBody )
{
    if ( SetPropertyString(PR_BODY,lpszBody,TRUE) )
    {
      SetMessageEditorFormat(EDITOR_FORMAT_PLAINTEXT);
      return TRUE;
    }
    return FALSE;
}

///////////////////////////////////////////////////////////////////////////////
//  Attachment management



///////////////////////////////////////////////////////////////////////////////
//  Raw property exposure

IMessage*
CMAPImessage::GetIMessage ( )
{
    return (IMessage *)m_pIMAPIProp;
}