📄 mapimessage.cpp
字号:
////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// 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 + -