⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mapimessage.cpp

📁 A (hopefully) complete extended MAPI wrapper for WinXP, WinCE, and .NET.
💻 CPP
📖 第 1 页 / 共 2 页
字号:
////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// File: MAPIMessage.cpp
// Description: MAPI Message class wrapper
//
// Copyright (C) 2005-2006, 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"

/////////////////////////////////////////////////////////////
// CMAPIMessage

CMAPIMessage::CMAPIMessage()
{
	m_pMessage=NULL;
	m_nAttachments=0;
	m_pMAPI=NULL;
	m_entry.cb=0;
	SetEntryID(NULL);
}

CMAPIMessage::CMAPIMessage(CMAPIMessage& message)
{
	m_pMessage=NULL;
	m_nAttachments=0;
	m_pMAPI=NULL;
	m_entry.cb=0;
	*this=message;
}

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

void CMAPIMessage::SetEntryID(SBinary* pEntry)
{
	if(m_entry.cb) delete [] m_entry.lpb;
	m_entry.lpb=NULL;

	if(pEntry) {
		m_entry.cb=pEntry->cb;
		if(m_entry.cb) {
			m_entry.lpb=new BYTE[m_entry.cb];
			memcpy(m_entry.lpb,pEntry->lpb,m_entry.cb);
		}
	} else {
		m_entry.cb=0;
	}
}

BOOL CMAPIMessage::Open(CMAPIEx* pMAPI,SBinary entry,DWORD dwMessageFlags)
{
	Close();
	m_pMAPI=pMAPI;
	m_dwMessageFlags=dwMessageFlags;
	ULONG ulObjType;
	if(m_pMAPI->GetSession()->OpenEntry(entry.cb,(LPENTRYID)entry.lpb,NULL,MAPI_BEST_ACCESS,&ulObjType,(LPUNKNOWN*)&m_pMessage)!=S_OK) return FALSE;

	SetEntryID(&entry);
	FillSenderName();
	FillSenderEmail();
	FillSubject();
	FillAttachmentCount();
	FillReceivedTime();
	
	return TRUE;
}

void CMAPIMessage::FillAttachmentCount()
{
	BOOL bHasAttachments=FALSE;
	LPSPropValue pProp;
	if(GetProperty(PR_HASATTACH,pProp)==S_OK) {
		bHasAttachments=pProp->Value.b;
		MAPIFreeBuffer(pProp);
	}

	if(bHasAttachments) {
		LPMAPITABLE pAttachTable=NULL;
		if(m_pMessage->GetAttachmentTable(0,&pAttachTable)!=S_OK) return;

		ULONG ulCount;
		if(pAttachTable->GetRowCount(0,&ulCount)==S_OK) {
			m_nAttachments=ulCount;
		}
		RELEASE(pAttachTable);
	}
}

void CMAPIMessage::Close()
{
	SetEntryID(NULL);
	RELEASE(m_pMessage);
	m_nAttachments=0;
	m_pMAPI=NULL;
	m_strBody=_T("");
	m_strRTF=_T("");
}

HRESULT CMAPIMessage::GetProperty(ULONG ulProperty,LPSPropValue &prop)
{
	ULONG ulPropCount;
	ULONG p[2]={ 1,ulProperty };
	return m_pMessage->GetProps((LPSPropTagArray)p, CMAPIEx::cm_nMAPICode, &ulPropCount, &prop);
}

LPCTSTR CMAPIMessage::GetBody()
{
	if(m_strBody.IsEmpty()) FillBody();
	return m_strBody;
}

LPCTSTR CMAPIMessage::GetRTF()
{
	if(m_strRTF.IsEmpty()) FillRTF();

	// does this RTF contain encoded HTML? If so decode it
	// code taken from Lucian Wischik's example at http://www.wischik.com/lu/programmer/mapi_utils.html
	if(m_strRTF.Find(_T("\\fromhtml"))!=-1) {
		LPCTSTR s=m_strRTF;

		// scan to <html tag
		// Ignore { and }. These are part of RTF markup.
		// Ignore \htmlrtf...\htmlrtf0. This is how RTF keeps its equivalent markup separate from the html.
		// Ignore \r and \n. The real carriage returns are stored in \par tags.
		// Ignore \pntext{..} and \liN and \fi-N. These are RTF junk.
		// Convert \par and \tab into \r\n and \t
		// Convert \'XX into the ascii character indicated by the hex number XX
		// Convert \{ and \} into { and }. This is how RTF escapes its curly braces.
		// When we get \*\mhtmltagN, keep the tag, but ignore the subsequent \*\htmltagN
		// When we get \*\htmltagN, keep the tag as long as it isn't subsequent to a \*\mhtmltagN
		// All other text should be kept as it is.

		while(*s) {
			if(_tcsnccmp(s,_T("<html"),5)==0) break;
			s++;
		}

		CString strHTML;
		int nTag=-1,nIgnoreTag=-1;
		while(*s) {
			if(*s==(TCHAR)'{') s++;
			else if(*s==(TCHAR)'}') s++;
			else if(*s==(TCHAR)'\r' || *s==(TCHAR)'\n') s++;
			else if(!_tcsnccmp(s,_T("\\*\\htmltag"),10)) {
				s+=10;
				nTag=0;
				while(*s>=(TCHAR)'0' && *s<=(TCHAR)'9') {
					nTag=nTag*10+*s-(TCHAR)'0';
					s++;
				}
				if(*s==(TCHAR)' ') s++;
				if(nTag==nIgnoreTag) {
					while(*s) {
						if(*s==(TCHAR)'}') break;
						s++;
					}
					nIgnoreTag=-1;
				}
			} else if(_tcsnccmp(s,_T("\\*\\mhtmltag"),11)==0) { 
				s+=11; 
				while(*s>=(TCHAR)'0' && *s<=(TCHAR)'9') {
					nTag=nTag*10+*s-(TCHAR)'0';
					s++;
				}
				if(*s==(TCHAR)' ') s++;
				nIgnoreTag=nTag;
			} else if(_tcsnccmp(s,_T("\\par"),4)==0) {
				strHTML+=_T("\r\n");
				s+=4;
				if(*s==(TCHAR)' ') s++;
			} else if(_tcsnccmp(s,_T("\\tab"),4)==0) {
				strHTML+=_T("\t");
				s+=4;
				if(*s==(TCHAR)' ') s++;
			} else if(_tcsnccmp(s,_T("\\li"),3)==0) { 
				s+=3; 
				while(*s>=(TCHAR)'0' && *s<=(TCHAR)'9') s++; 
				if(*s==(TCHAR)' ') s++;
			} else if(_tcsnccmp(s,_T("\\fi-"),4)==0) { 
				s+=4; 
				while(*s>=(TCHAR)'0' && *s<=(TCHAR)'9') s++; 
				if(*s==(TCHAR)' ') s++;
			} else if(_tcsnccmp(s,_T("\\'"),2)==0) { 
				TCHAR hi=s[2],lo=s[3];
				if(hi>='0' && hi<='9') hi-='0'; else if(hi>='A' && hi<='Z') hi=hi-'A'+10; else if(hi>='a' && hi<='z') hi=hi-'a'+10;
				if(lo>='0' && lo<='9') lo-='0'; else if(lo>='A' && lo<='Z') lo=lo-'A'+10; else if(lo>='a' && lo<='z') lo=lo-'a'+10;
				strHTML+=(TCHAR)(hi*16+lo);
				s+=4;
			} else if(_tcsnccmp(s,_T("\\pntext"),7)==0) {
				s+=7; 
				while(*s) {
					if(*s==(TCHAR)'}') break;
					s++;
				}
			} else if(_tcsnccmp(s,_T("\\htmlrtf"),8)==0) {
				s+=8;
				while(*s) {
					if(_tcsnccmp(s,_T("\\htmlrtf0"),9)==0) {
						s+=9;
						if(*s==(TCHAR)' ') s++;
						break;
					}
					s++;
				}
			} else if(_tcsnccmp(s,_T("\\{"),2)==0) { 
				strHTML+='{';
				s+=2;
			} else if(_tcsnccmp(s,_T("\\}"),2)==0) { 
				strHTML+='}';
				s+=2;
			} else {
				strHTML+=*s;
				s++;
			}
		}
		m_strRTF=strHTML;
	}
	return m_strRTF;
}

void CMAPIMessage::FillSenderName()
{
	LPSPropValue pProp;
	if(GetProperty(PR_SENDER_NAME,pProp)==S_OK) {
		m_strSenderName=CMAPIEx::GetValidString(*pProp);
		MAPIFreeBuffer(pProp);
	}
	else m_strSenderName=_T("");
}

void CMAPIMessage::FillSenderEmail()
{
	CString strAddrType;
	LPSPropValue pProp;
	if(GetProperty(PR_SENDER_ADDRTYPE,pProp)==S_OK) {
		strAddrType=CMAPIEx::GetValidString(*pProp);
		MAPIFreeBuffer(pProp);
	}

	if(GetProperty(PR_SENDER_EMAIL_ADDRESS,pProp)==S_OK) {
		m_strSenderEmail=CMAPIEx::GetValidString(*pProp);
		MAPIFreeBuffer(pProp);
	}
	else m_strSenderEmail=_T("");

#ifndef _WIN32_WCE
	// for Microsoft Exchange server internal mails we want to try to resolve the SMTP email address
	if(strAddrType=="EX") {
		if(GetProperty(PR_SENDER_ENTRYID,pProp)==S_OK) {
			LPADRBOOK pAddressBook;
			if(m_pMAPI->GetSession()->OpenAddressBook(0, NULL, AB_NO_DIALOG, &pAddressBook)==S_OK) {
				ULONG ulObjType;
				IMailUser* pMailUser;
				if(pAddressBook->OpenEntry(pProp->Value.bin.cb,(ENTRYID*)pProp->Value.bin.lpb,NULL,MAPI_BEST_ACCESS,&ulObjType,(LPUNKNOWN*)&pMailUser)==S_OK) {
					if(ulObjType==MAPI_MAILUSER) {
						MAPIFreeBuffer(pProp);
						ULONG ulPropCount;
						ULONG p[2]={ 1,PR_SMTP_ADDRESS };
						if(pMailUser->GetProps((LPSPropTagArray)p, CMAPIEx::cm_nMAPICode, &ulPropCount, &pProp)==S_OK) {
							m_strSenderEmail=CMAPIEx::GetValidString(*pProp);
						}
					}
					RELEASE(pMailUser);
				}
				RELEASE(pAddressBook);
			}
			MAPIFreeBuffer(pProp);
		}
	}
#endif
}

void CMAPIMessage::FillSubject()
{
	LPSPropValue pProp;
	if(GetProperty(PR_SUBJECT,pProp)==S_OK) {
		m_strSubject=CMAPIEx::GetValidString(*pProp);
		MAPIFreeBuffer(pProp);
	}
	else m_strSubject=_T("");
}

void CMAPIMessage::FillRTF()
{
	m_strRTF=_T("");
	IStream* pStream;
	if(m_pMessage->OpenProperty(PR_RTF_COMPRESSED,&IID_IStream,STGM_READ,0,(LPUNKNOWN*)&pStream)!=S_OK) return;

#ifdef _WIN32_WCE
	const int BUF_SIZE=1024;
#else
	const int BUF_SIZE=16384;
#endif
	char szBuf[BUF_SIZE+1];
	ULONG ulNumChars;

	IStream *pUncompressed;
	if(WrapCompressedRTFStream(pStream,0,&pUncompressed)==S_OK) {
		do {
			pUncompressed->Read(szBuf,BUF_SIZE,&ulNumChars);
			szBuf[min(BUF_SIZE,ulNumChars)]=0;
			m_strRTF+=szBuf;
		} while(ulNumChars>=BUF_SIZE);
		RELEASE(pUncompressed);
	}

	RELEASE(pStream);
}

void CMAPIMessage::FillBody()
{
	m_strBody=_T("");
	IStream* pStream;
	if(m_pMessage->OpenProperty(PR_BODY,&IID_IStream,STGM_READ,NULL,(LPUNKNOWN*)&pStream)!=S_OK) return;

#ifdef _WIN32_WCE
	const int BUF_SIZE=1024;
#else
	const int BUF_SIZE=16384;
#endif
	TCHAR szBuf[BUF_SIZE+1];
	ULONG ulNumChars;
	
	do {
		pStream->Read(szBuf,BUF_SIZE*sizeof(TCHAR),&ulNumChars);
		ulNumChars/=sizeof(TCHAR);
		szBuf[min(BUF_SIZE,ulNumChars)]=0;
		m_strBody+=szBuf;
	} while(ulNumChars>=BUF_SIZE);

	RELEASE(pStream);
}

void  CMAPIMessage::FillReceivedTime()
{
	LPSPropValue pProp;
	if(GetProperty(PR_MESSAGE_DELIVERY_TIME,pProp)==S_OK) {
		m_tmReceived=CTime(pProp->Value.ft);
		MAPIFreeBuffer(pProp);
	}
}

LPCTSTR CMAPIMessage::GetReceivedTime(LPCTSTR szFormat)
{
	static CString strTime;
	CString strFormat=szFormat ? szFormat : _T("%m/%d/%Y %I:%M %p");
	strTime=m_tmReceived.Format(strFormat);
	return strTime;
}

LPCTSTR CMAPIMessage::GetAttachmentName(int nIndex)
{
	static CString strAttachmentName;
	strAttachmentName=_T("");

	LPMAPITABLE pAttachTable=NULL;
	if(m_pMessage->GetAttachmentTable(0,&pAttachTable)==S_OK)
	{
		enum { PROP_ATTACH_LONG_FILENAME, PROP_ATTACH_FILENAME, ATTACH_COLS };
		static SizedSPropTagArray(ATTACH_COLS,Columns)={ATTACH_COLS, PR_ATTACH_LONG_FILENAME, PR_ATTACH_FILENAME };
		ULONG ulCount;
		if(pAttachTable->SetColumns((LPSPropTagArray)&Columns,0)==S_OK &&
			pAttachTable->GetRowCount(0,&ulCount)==S_OK && nIndex < (int)ulCount)
		{
			LPSRowSet pRows=NULL;
			if(pAttachTable->QueryRows(ulCount,0,&pRows)!=S_OK) MAPIFreeBuffer(pRows);
			else {
				if(nIndex < (int)pRows->cRows) {
					if(CMAPIEx::GetValidString(pRows->aRow[nIndex].lpProps[PROP_ATTACH_LONG_FILENAME])) strAttachmentName=pRows->aRow[nIndex].lpProps[PROP_ATTACH_LONG_FILENAME].Value.LPSZ;
					else if(CMAPIEx::GetValidString(pRows->aRow[nIndex].lpProps[PROP_ATTACH_FILENAME])) strAttachmentName=pRows->aRow[nIndex].lpProps[PROP_ATTACH_FILENAME].Value.LPSZ;
					else strAttachmentName=_T("");
				}
				FreeProws(pRows);
			}
		}
		RELEASE(pAttachTable);
	}
	return strAttachmentName;
}

BOOL CMAPIMessage::SaveAttachment(LPATTACH pAttachment,LPCTSTR szPath)
{
	CFile file;
	if(!file.Open(szPath,CFile::modeCreate | CFile::modeWrite)) return FALSE;

	IStream* pStream;
	if(pAttachment->OpenProperty(PR_ATTACH_DATA_BIN,&IID_IStream,STGM_READ,NULL,(LPUNKNOWN*)&pStream)!=S_OK) {
		file.Close();
		return FALSE;
	}

	const int BUF_SIZE=4096;
	BYTE b[BUF_SIZE];
	ULONG ulRead;

	do {
		pStream->Read(&b,BUF_SIZE,&ulRead);
		if(ulRead) file.Write(b,ulRead);
	} while(ulRead>=BUF_SIZE);

	file.Close();
	RELEASE(pStream);
	return TRUE;
}

// use nIndex of -1 to save all attachments to szFolder
BOOL CMAPIMessage::SaveAttachments(LPCTSTR szFolder,int nIndex)
{
	LPMAPITABLE pAttachTable=NULL;
	if(m_pMessage->GetAttachmentTable(0,&pAttachTable)!=S_OK) return FALSE;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -