////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// File: MAPIAttachment.cpp
// Description: MAPI Attachment class wrapper
//
// Copyright (C) 2005-2011, Noel Dillabough
//
// This source code is free to use and modify provided this notice remains intact and that any enhancements
// or bug fixes are posted to the CodeProject page hosting this class for the community to benefit.
//
// Usage: see the CodeProject article at http://www.codeproject.com/internet/CMapiEx.asp
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include "MAPIExPCH.h"
#include "MAPIEx.h"

/////////////////////////////////////////////////////////////
// MAPIAttachment

CMAPIAttachment::CMAPIAttachment()
{
	m_pStream=NULL;
	m_nBytesWritten=0;
}

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

void CMAPIAttachment::Attach(LPATTACH pAttachment)
{
	Close();
	m_pItem=pAttachment;
}

LPATTACH CMAPIAttachment::Detach()
{
	LPATTACH pAttachment=Attachment();
	m_pItem=NULL;
	return pAttachment;
}

BOOL CMAPIAttachment::Create(LPMESSAGE pMessage)
{
	Close();

	BOOL bResult=FALSE;
	if(pMessage)
	{
		LPATTACH pAttachment;
		ULONG ulAttachmentNum=0;

		if(pMessage->CreateAttach(NULL, 0, &ulAttachmentNum, &pAttachment)==S_OK) 
		{
			m_pItem=pAttachment;

			const int nProperties=2;
			SPropValue prop[nProperties];
			memset(prop, 0,sizeof(SPropValue)*nProperties);
			prop[0].ulPropTag=PR_ATTACH_METHOD;
			prop[0].Value.ul=ATTACH_BY_VALUE;
			prop[1].ulPropTag=PR_RENDERING_POSITION;
			prop[1].Value.l=1;
			if(pAttachment->SetProps(nProperties, prop, NULL)==S_OK) 
			{
				bResult=TRUE;
			}
		}
	}
	return bResult;
}

BOOL CMAPIAttachment::Open(LPMESSAGE pMessage, int nIndex)
{
	Close();

	BOOL bResult=FALSE;
	LPMAPITABLE pAttachTable;
	if(nIndex>=0 && pMessage && pMessage->GetAttachmentTable(0, &pAttachTable)==S_OK) 
	{
		enum { PROP_ATTACH_NUM, ATTACH_COLS };
		static SizedSPropTagArray(ATTACH_COLS, Columns)={ATTACH_COLS, PR_ATTACH_NUM };
		if(pAttachTable->SetColumns((LPSPropTagArray)&Columns, 0)==S_OK)
		{
			if(pAttachTable->SeekRow(BOOKMARK_BEGINNING, nIndex, NULL)==S_OK)
			{
				LPSRowSet pRows=NULL;
				if(pAttachTable->QueryRows(1, 0, &pRows)==S_OK) 
				{
					if(pRows->cRows > 0)
					{
						LPATTACH pAttachment;
						if(pMessage->OpenAttach(pRows->aRow[0].lpProps[PROP_ATTACH_NUM].Value.ul, NULL, 0, &pAttachment)==S_OK)
						{
							m_pItem=pAttachment;
							bResult=TRUE;
						}
					}
					FreeProws(pRows);
				}
			}
		}
	}
	return bResult;
}

void CMAPIAttachment::Close()
{
	CloseStream();
	CMAPIObject::Close();
}

BOOL CMAPIAttachment::GetDisplayName(CString& strDisplayName)
{
	return GetPropertyString(PR_DISPLAY_NAME, strDisplayName);
}

BOOL CMAPIAttachment::GetFileName(CString& strFileName)
{
	return GetPropertyString(PR_ATTACH_FILENAME, strFileName);
}

BOOL CMAPIAttachment::GetLongFileName(CString& strLongFileName)
{
	return GetPropertyString(PR_ATTACH_LONG_FILENAME, strLongFileName);
}

BOOL CMAPIAttachment::GetCID(CString& strCID)
{
	return GetPropertyString(PR_ATTACH_CONTENT_ID, strCID);
}

BOOL CMAPIAttachment::SetDisplayName(LPCTSTR szDisplayName)
{
	return SetPropertyString(PR_DISPLAY_NAME, szDisplayName);
}

BOOL CMAPIAttachment::SetFileName(LPCTSTR szFileName)
{
	return SetPropertyString(PR_ATTACH_FILENAME, szFileName);
}

BOOL CMAPIAttachment::SetLongFileName(LPCTSTR szLongFileName)
{
	return SetPropertyString(PR_ATTACH_LONG_FILENAME, szLongFileName);
}

BOOL CMAPIAttachment::SetCID(LPCTSTR szCID)
{
	return SetPropertyString(PR_ATTACH_CONTENT_ID, szCID);
}

BOOL CMAPIAttachment::OpenStream(BOOL bCreate)
{
	if(m_pItem) 
	{
		ULONG ulInterfaceOptions=STGM_READ;
		ULONG ulFlags=0;
		if(bCreate)
		{
			ulInterfaceOptions=0;
			ulFlags=MAPI_MODIFY | MAPI_CREATE;
		}
		return (m_pItem->OpenProperty(PR_ATTACH_DATA_BIN, &IID_IStream, ulInterfaceOptions, ulFlags, (LPUNKNOWN*)&m_pStream)==S_OK);
	}
	return FALSE;
}

int CMAPIAttachment::Read(BYTE* pData, int nCount)
{
	if(m_pStream)
	{
		ULONG ulRead;
		m_pStream->Read(pData, nCount, &ulRead);
		return ulRead;
	}
	return -1;
}

int CMAPIAttachment::Write(BYTE* pData, int nCount)
{
	if(m_pStream)
	{
		ULONG ulWritten;
		m_pStream->Write(pData, nCount, &ulWritten);
		m_nBytesWritten+=ulWritten;
		return ulWritten;
	}
	return -1;
}

void CMAPIAttachment::CloseStream()
{
	if(m_pStream)
	{
		m_pStream->Commit(STGC_DEFAULT);
		RELEASE(m_pStream);
		SetPropertyValue(PR_ATTACH_SIZE, m_nBytesWritten);
		m_nBytesWritten=0;
	}
}

BOOL CMAPIAttachment::LoadAttachment(LPCTSTR szPath)
{
	CFile file;
	if(file.Open(szPath, CFile::modeRead) && OpenStream(TRUE))
	{
		const int BUF_SIZE=4096;
		BYTE pData[BUF_SIZE];
		ULONG ulRead;

		ulRead=file.Read(pData, BUF_SIZE);
		while(ulRead) 
		{
			Write(pData, ulRead);
			ulRead=file.Read(pData, BUF_SIZE);
		}

		file.Close();
		CloseStream();
		return TRUE;
	}
	return FALSE;
}

BOOL CMAPIAttachment::SaveAttachment(LPCTSTR szPath)
{
	CFile file;
	if(file.Open(szPath, CFile::modeCreate | CFile::modeWrite) && OpenStream(FALSE))
	{
		const int BUF_SIZE=4096;
		BYTE pData[BUF_SIZE];
		ULONG ulRead;

		do {
			ulRead=Read(pData, BUF_SIZE);
			if(ulRead) file.Write(pData, ulRead);
		} while(ulRead>=BUF_SIZE);


		file.Close();
		CloseStream();
		return TRUE;
	}
	return FALSE;
}
