/// /// Copyright © 2003-2008 JetBrains s.r.o. /// You may distribute under the terms of the GNU General Public License, as published by the Free Software Foundation, version 2 (see License.txt in the repository root folder). /// #pragma unmanaged #include "emessage.h" #include "ESPropValue.h" #include "ETable.h" #include "EAttach.h" #include "guard.h" #include "RCPtrDef.h" #include // {00020D0B-0000-0000-C000-000000000046} DEFINE_GUID( CLSID_MailMessage, 0x00020D0B, 0x0000, 0x0000, 0xC0, 0x00, 0x0, 0x00, 0x0, 0x00, 0x00, 0x46 ); template RCPtr; #ifdef EMAPI_MANAGED #pragma managed #endif EMessage::EMessage( LPMESSAGE lpMessage ) : MAPIProp( lpMessage ) { if ( lpMessage == NULL ) { Guard::ThrowArgumentNullException( "lpMessage" ); } _lpMessage = lpMessage; } EMessage::~EMessage() { _lpMessage = NULL; } void EMessage::CopyTo( const EMessageSPtr& destMessage ) const { MAPIProp::CopyTo( &IID_IMessage, destMessage->_lpMessage ); } LPMESSAGE EMessage::GetRaw() const { return _lpMessage; } int EMessage::GetInternetCPID() const { ESPropValueSPtr prop = getSingleProp( (int)0x3FDE0003 ); if ( !prop.IsNull() ) { return prop->GetLong(); } return 0; } void EMessage::SetConversation( const EMessageSPtr& parent ) const { ESPropValueSPtr prop = parent->getSingleProp( (int)PR_CONVERSATION_INDEX ); if ( !prop.IsNull() ) { SPropValue pChildConvIndex[1]; pChildConvIndex[0].ulPropTag = (int)PR_CONVERSATION_INDEX; HRESULT hr = ScCreateConversationIndex( prop->GetBinCB(), prop->GetBinLPBYTE(), &pChildConvIndex[0].Value.bin.cb, &pChildConvIndex[0].Value.bin.lpb ); hr = _lpMessage->SetProps( 1, pChildConvIndex, NULL); } } void EMessage::RTFSyncBody() const { ESPropValueSPtr rtfSync = getSingleProp( (int)PR_RTF_IN_SYNC ); if ( !rtfSync.IsNull() ) { if ( !rtfSync->GetBool() ) { BOOL fUpdated = FALSE; ::RTFSync( _lpMessage, (int)RTF_SYNC_BODY_CHANGED, &fUpdated ); } } } void EMessage::RTFSyncRTF() const { BOOL fUpdated = FALSE; ::RTFSync( _lpMessage, (int)RTF_SYNC_RTF_CHANGED, &fUpdated ); } #define PR_RECIPIENT_FLAGS 0x5FFD0003 #define PR_SEND_INTERNET_ENCODING 0x3A710003 #define PR_RECIPIENT_ENTRYID 0x5FF70102 #define PR_RECIPIENT_TRACKSTATUS 0x5FFF0003 #define PR_RECIPIENT_DISPLAY_NAME 0x5FF6001E void EMessage::AddRecipient( ELPSRowSetSPtr row, int /*recType*/ ) const { HRESULT hr = _lpMessage->ModifyRecipients( (int)MODRECIP_ADD, (LPADRLIST)row.get()->GetRaw() ); Guard::CheckHR( hr ); } HRESULT EMessage::AddRecipient( LPMAPISESSION pSession, LPWSTR displayName, LPWSTR email, LPSTR displayNameA, LPSTR emailA, bool unicode, int recType ) const { HRESULT hRes = S_OK; // Status code of MAPI calls LPADRLIST pAdrList = NULL; // ModifyRecips takes LPADRLIST LPADRBOOK lpAddrBook = NULL; enum { NAME, ADDR, EMAIL, RECIP, EID, RICH_INFO, RECIPIENT_TYPE, FORMAT, RECIPIENT_ENTRYID, TRACKSTATUS, OBJTYPE, DISPLAY_TYPE, RECIPIENT_DISPLAY_NAME, NUM_RECIP_PROPS = 13 }; // Allocate memory for new SRowSet structure. hRes = MAPIAllocateBuffer( CbNewSRowSet(1), (LPVOID*) &pAdrList); if (FAILED(hRes)) goto Quit; // Zero out allocated memory. ZeroMemory( pAdrList, CbNewSRowSet(1) ); // Allocate memory for SPropValue structure that indicates what // recipient properties will be set. NUM_RECIP_PROPS == 5. hRes = MAPIAllocateBuffer( NUM_RECIP_PROPS * sizeof(SPropValue), (LPVOID*) &(pAdrList->aEntries[0].rgPropVals)); if (FAILED(hRes)) goto Quit; // Zero out allocated memory. ZeroMemory(pAdrList -> aEntries[0].rgPropVals, NUM_RECIP_PROPS * sizeof(SPropValue) ); // Setup the One Time recipient by indicating how many // recipients and how many properties will be set on each // recipient. pAdrList->cEntries = 1; // How many recipients. // How many properties per recipient pAdrList->aEntries[0].cValues = NUM_RECIP_PROPS; if ( unicode ) { // Set the SPropValue members == the desired values. pAdrList->aEntries[0].rgPropVals[NAME].ulPropTag = (int)PR_DISPLAY_NAME_W; pAdrList->aEntries[0].rgPropVals[NAME].Value.lpszW = displayName; pAdrList->aEntries[0].rgPropVals[RECIPIENT_DISPLAY_NAME].ulPropTag = (int)PR_RECIPIENT_DISPLAY_NAME; pAdrList->aEntries[0].rgPropVals[RECIPIENT_DISPLAY_NAME].Value.lpszW = displayName; pAdrList->aEntries[0].rgPropVals[ADDR].ulPropTag = (int)PR_ADDRTYPE_W; pAdrList->aEntries[0].rgPropVals[EMAIL].ulPropTag = (int)PR_EMAIL_ADDRESS_W; pAdrList->aEntries[0].rgPropVals[EMAIL].Value.lpszW = email; if ( email != NULL && wcscspn( email, L"/" ) == 0 ) { pAdrList->aEntries[0].rgPropVals[ADDR].Value.lpszW = L"EX"; } else { pAdrList->aEntries[0].rgPropVals[ADDR].Value.lpszW = L"SMTP"; } } else { // Set the SPropValue members == the desired values. pAdrList->aEntries[0].rgPropVals[NAME].ulPropTag = (int)PR_DISPLAY_NAME_A; pAdrList->aEntries[0].rgPropVals[NAME].Value.lpszA = displayNameA; pAdrList->aEntries[0].rgPropVals[RECIPIENT_DISPLAY_NAME].ulPropTag = (int)PR_RECIPIENT_DISPLAY_NAME; pAdrList->aEntries[0].rgPropVals[RECIPIENT_DISPLAY_NAME].Value.lpszA = displayNameA; pAdrList->aEntries[0].rgPropVals[ADDR].ulPropTag = (int)PR_ADDRTYPE_A; pAdrList->aEntries[0].rgPropVals[EMAIL].ulPropTag = (int)PR_EMAIL_ADDRESS_A; pAdrList->aEntries[0].rgPropVals[EMAIL].Value.lpszA = emailA; if ( email != NULL && wcscspn( email, L"/" ) == 0 ) { pAdrList->aEntries[0].rgPropVals[ADDR].Value.lpszA = "EX"; } else { pAdrList->aEntries[0].rgPropVals[ADDR].Value.lpszA = "SMTP"; } } pAdrList->aEntries[0].rgPropVals[RECIP].ulPropTag = (int)PR_RECIPIENT_TYPE; pAdrList->aEntries[0].rgPropVals[RECIP].Value.l = recType; pAdrList->aEntries[0].rgPropVals[EID].ulPropTag = (int)PR_ENTRYID; pAdrList->aEntries[0].rgPropVals[RECIPIENT_ENTRYID].ulPropTag = (int)PR_RECIPIENT_ENTRYID; pAdrList->aEntries[0].rgPropVals[RICH_INFO].ulPropTag = (int)PR_SEND_RICH_INFO; pAdrList->aEntries[0].rgPropVals[RICH_INFO].Value.b = 0; pAdrList->aEntries[0].rgPropVals[RECIPIENT_TYPE].ulPropTag = (int)PR_RECIPIENT_FLAGS; pAdrList->aEntries[0].rgPropVals[RECIPIENT_TYPE].Value.l = 1; pAdrList->aEntries[0].rgPropVals[FORMAT].ulPropTag = (int)PR_SEND_INTERNET_ENCODING; pAdrList->aEntries[0].rgPropVals[FORMAT].Value.l = 393216; pAdrList->aEntries[0].rgPropVals[TRACKSTATUS].ulPropTag = (int)PR_RECIPIENT_TRACKSTATUS; pAdrList->aEntries[0].rgPropVals[TRACKSTATUS].Value.l = 0; pAdrList->aEntries[0].rgPropVals[OBJTYPE].ulPropTag = (int)PR_OBJECT_TYPE; pAdrList->aEntries[0].rgPropVals[OBJTYPE].Value.l = 6; pAdrList->aEntries[0].rgPropVals[DISPLAY_TYPE].ulPropTag = (int)PR_DISPLAY_TYPE; pAdrList->aEntries[0].rgPropVals[DISPLAY_TYPE].Value.l = 0; hRes = pSession->OpenAddressBook(0, NULL, (int)AB_NO_DIALOG, &lpAddrBook); if (FAILED(hRes)) goto Quit; // Create the One-off address and get an EID for it. hRes = lpAddrBook->CreateOneOff( pAdrList->aEntries[0].rgPropVals[NAME].Value.lpszA, pAdrList->aEntries[0].rgPropVals[ADDR].Value.lpszA, pAdrList->aEntries[0].rgPropVals[EMAIL].Value.lpszA, MAPI_SEND_NO_RICH_INFO | MAPI_UNICODE, &pAdrList->aEntries[0].rgPropVals[EID].Value.bin.cb, (LPENTRYID*) (&pAdrList->aEntries[0].rgPropVals[EID].Value.bin.lpb)); if (FAILED(hRes)) goto Quit; int cb = pAdrList->aEntries[0].rgPropVals[EID].Value.bin.cb; hRes = lpAddrBook->ResolveName( 0L, 0L, NULL, pAdrList ); if (FAILED(hRes)) goto Quit; cb = pAdrList->aEntries[0].rgPropVals[EID].Value.bin.cb; pAdrList->aEntries[0].rgPropVals[RECIPIENT_ENTRYID].ulPropTag = (int)PR_RECIPIENT_ENTRYID; pAdrList->aEntries[0].rgPropVals[RECIPIENT_ENTRYID].Value.bin.cb = cb; if ( cb > 24 ) { LPBYTE byte = pAdrList->aEntries[0].rgPropVals[EID].Value.bin.lpb + 22; *byte = 0x07; byte = pAdrList->aEntries[0].rgPropVals[EID].Value.bin.lpb + 23; *byte = 0x80; } pAdrList->aEntries[0].rgPropVals[RECIPIENT_ENTRYID].Value.bin.lpb = NULL; hRes = MAPIAllocateBuffer( cb, (void **)&pAdrList->aEntries[0].rgPropVals[RECIPIENT_ENTRYID].Value.bin.lpb ); if (FAILED(hRes)) goto Quit; CopyMemory( pAdrList->aEntries[0].rgPropVals[RECIPIENT_ENTRYID].Value.bin.lpb, pAdrList->aEntries[0].rgPropVals[EID].Value.bin.lpb, cb ); pAdrList->aEntries[0].rgPropVals[RICH_INFO].ulPropTag = (int)PR_SEND_RICH_INFO; pAdrList->aEntries[0].rgPropVals[RICH_INFO].Value.b = 0; // If everything goes right, add the new recipient to the // message object passed into us. hRes = _lpMessage->ModifyRecipients( (int)MODRECIP_ADD, pAdrList ); if (FAILED(hRes)) goto Quit; Quit: // Always release any newly created objects and // allocated memory. FreePadrlist( pAdrList ); UlRelease( lpAddrBook ); return hRes; } void EMessage::AttachFile( LPSTR path, LPSTR fileName ) const { LPSTREAM pStrmSrc = NULL; enum { FILENAME, METHOD, RENDERING, NUM_ATT_PROPS }; SPropValue spvAttach[NUM_ATT_PROPS]; HRESULT hRes = OpenStreamOnFile(MAPIAllocateBuffer, MAPIFreeBuffer, STGM_READ, path, NULL, &pStrmSrc ); if ( !FAILED( hRes )) { ULONG ulAttNum; LPATTACH pAtt = NULL; hRes = _lpMessage->CreateAttach( NULL, 0, &ulAttNum, &pAtt ); if ( !FAILED( hRes ) ) { LPSTREAM pStrmDest = NULL; hRes = pAtt->OpenProperty( (int)PR_ATTACH_DATA_BIN, (LPIID)&IID_IStream, 0, (int)(MAPI_MODIFY | MAPI_CREATE), (LPUNKNOWN *)&pStrmDest ); if ( !FAILED( hRes ) ) { STATSTG StatInfo; pStrmSrc->Stat( &StatInfo, STATFLAG_NONAME ); hRes = pStrmSrc->CopyTo( pStrmDest, StatInfo.cbSize, NULL, NULL ); if ( !FAILED( hRes ) ) { spvAttach[FILENAME].ulPropTag = (int)PR_ATTACH_FILENAME; spvAttach[FILENAME].Value.lpszA = fileName; spvAttach[METHOD].ulPropTag = (int)PR_ATTACH_METHOD; spvAttach[METHOD].Value.l = (int)ATTACH_BY_VALUE; spvAttach[RENDERING].ulPropTag = (int)PR_RENDERING_POSITION; spvAttach[RENDERING].Value.l = -1; hRes = pAtt->SetProps( (int)NUM_ATT_PROPS, (LPSPropValue)&spvAttach, NULL ); if ( !FAILED( hRes ) ) { pAtt->SaveChanges( 0 ); } } } if ( pStrmDest ) pStrmDest->Release(); } if ( pAtt ) pAtt->Release(); } if ( pStrmSrc ) pStrmSrc->Release(); } void EMessage::Submit() const { HRESULT hr = _lpMessage->SubmitMessage( 0 ); hr = hr; } ESPropValueSPtr EMessage::GetStatus() const { const SizedSPropTagArray( 4, atProps ) = { 4, (int)PR_MSG_STATUS, (int)PR_MESSAGE_FLAGS, (int)PR_ACCESS_LEVEL, (int)PR_MESSAGE_CLASS }; unsigned long ulTmp = 0; LPSPropValue pVal = 0; HRESULT hr = _lpMessage->GetProps( (LPSPropTagArray)&atProps, 0, &ulTmp, &pVal ); if ( SUCCEEDED( hr ) ) { return TypeFactory::CreateESPropValue( pVal ); } return ESPropValueSPtr( NULL ); } void EMessage::SetUnRead( bool unread ) const { if ( unread ) { _lpMessage->SetReadFlag( (int)CLEAR_READ_FLAG ); } else { _lpMessage->SetReadFlag( 0 ); } } bool EMessage::Unread() const { ESPropValueSPtr prop = getSingleProp( (int)PR_MESSAGE_FLAGS ); if ( !prop.IsNull() ) { int value = prop->GetLong(); return ( ( value & 1 ) != 1 ); } return false; } ETableSPtr EMessage::GetRecipientsTable() const { LPMAPITABLE lpRecips = NULL; HRESULT hr = _lpMessage->GetRecipientTable( 0, &lpRecips ); if ( hr == S_OK ) { return TypeFactory::CreateETable( lpRecips ); } return ETableSPtr( NULL ); } ETableSPtr EMessage::GetAttachmentTable() const { LPMAPITABLE lpAttachments = NULL; HRESULT hr = _lpMessage->GetAttachmentTable( 0, &lpAttachments ); if ( hr == S_OK ) { return TypeFactory::CreateAttachmentsETable( lpAttachments ); } return ETableSPtr( NULL ); } EAttachSPtr EMessage::OpenAttach( int attachmentNum ) const { LPATTACH lpAttach = NULL; HRESULT hr = _lpMessage->OpenAttach( attachmentNum, &IID_IAttachment, 0, &lpAttach ); if ( hr == S_OK ) { return TypeFactory::CreateEAttach( lpAttach ); } return EAttachSPtr( NULL ); } HRESULT EMessage::SaveToMSG( LPSTR szPath ) { LPMALLOC pMalloc = MAPIGetDefaultMalloc(); if ( pMalloc == NULL ) return E_FAIL; LPWSTR lpWideCharStr = NULL; ULONG cbStrSize = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, szPath, -1, lpWideCharStr, 0); HRESULT hr = MAPIAllocateBuffer( cbStrSize * sizeof(WCHAR), (LPVOID *)&lpWideCharStr ); Guard::CheckHR( hr ); MAPIBuffer mapiBuffer( hr, lpWideCharStr ); MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, szPath, -1, lpWideCharStr, cbStrSize ); LPSTORAGE pStorage = NULL; HRESULT hRes = ::StgCreateDocfile(lpWideCharStr, STGM_READWRITE | STGM_TRANSACTED | STGM_CREATE, 0, &pStorage ); if ( hRes == S_OK ) { LPMSGSESS pMsgSession = NULL; hRes = ::OpenIMsgSession( pMalloc, 0, &pMsgSession ); if ( hRes == S_OK ) { LPMESSAGE pIMsg = NULL; hRes = ::OpenIMsgOnIStg( pMsgSession, MAPIAllocateBuffer, MAPIAllocateMore, MAPIFreeBuffer, pMalloc, NULL, pStorage, NULL, 0, 0, &pIMsg ); if ( hRes == S_OK ) { hRes = WriteClassStg( pStorage, CLSID_MailMessage ); if ( hRes == S_OK ) { SizedSPropTagArray ( 7, excludeTags ); excludeTags.cValues = 7; excludeTags.aulPropTag[0] = PR_ACCESS; excludeTags.aulPropTag[1] = PR_BODY; excludeTags.aulPropTag[2] = PR_RTF_SYNC_BODY_COUNT; excludeTags.aulPropTag[3] = PR_RTF_SYNC_BODY_CRC; excludeTags.aulPropTag[4] = PR_RTF_SYNC_BODY_TAG; excludeTags.aulPropTag[5] = PR_RTF_SYNC_PREFIX_COUNT; excludeTags.aulPropTag[6] = PR_RTF_SYNC_TRAILING_COUNT; hRes = _lpMessage->CopyTo( 0, NULL, (LPSPropTagArray)&excludeTags, NULL, NULL, (LPIID)&IID_IMessage, pIMsg, 0, NULL ); if ( hRes == S_OK ) { pIMsg->SaveChanges( (int)KEEP_OPEN_READWRITE ); hRes = pStorage->Commit( STGC_DEFAULT ); } } pIMsg->Release(); } CloseIMsgSession( pMsgSession ); } pStorage->Release(); } return hRes; } #define STGM_DIRECT_SWMR 0x00400000L EMessageSPtr EMessage::LoadFromMSG( LPSTR szPath ) { LPMALLOC pMalloc = MAPIGetDefaultMalloc(); if ( pMalloc == NULL ) return EMessageSPtr( NULL ); LPWSTR lpWideCharStr = NULL; ULONG cbStrSize = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, szPath, -1, lpWideCharStr, 0); HRESULT hr = MAPIAllocateBuffer( cbStrSize * sizeof(WCHAR), (LPVOID *)&lpWideCharStr ); Guard::CheckHR( hr ); MAPIBuffer mapiBuffer( hr, lpWideCharStr ); MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, szPath, -1, lpWideCharStr, cbStrSize ); LPSTORAGE pStorage = NULL; HRESULT hRes = ::StgOpenStorage( lpWideCharStr, NULL, STGM_DIRECT_SWMR | STGM_READ | STGM_SHARE_DENY_NONE, NULL, 0, &pStorage ); if ( hRes == S_OK ) { LPMSGSESS pMsgSession = NULL; hRes = ::OpenIMsgSession( pMalloc, 0, &pMsgSession ); if ( hRes == S_OK ) { LPMESSAGE pIMsg = NULL; hRes = ::OpenIMsgOnIStg( pMsgSession, MAPIAllocateBuffer, MAPIAllocateMore, MAPIFreeBuffer, pMalloc, NULL, pStorage, NULL, 0, 0, &pIMsg ); if ( hRes == S_OK ) { return TypeFactory::CreateEMessage( pIMsg ); } CloseIMsgSession( pMsgSession ); } pStorage->Release(); } return EMessageSPtr( NULL ); }