void CMapiFolderList::DumpList( void) { CMapiFolder *pFolder; nsString str; int depth; char prefix[256]; MAPI_TRACE0( "Folder List ---------------------------------\n"); for (int i = 0; i < m_array.Count(); i++) { pFolder = (CMapiFolder *)GetAt( i); depth = pFolder->GetDepth(); pFolder->GetDisplayName( str); depth *= 2; if (depth > 255) depth = 255; memset( prefix, ' ', depth); prefix[depth] = 0; #ifdef MAPI_DEBUG char *ansiStr = ToNewCString(str); MAPI_TRACE2( "%s%s: ", prefix, ansiStr); NS_Free(ansiStr); #endif pFolder->GetFilePath( str); #ifdef MAPI_DEBUG ansiStr = ToNewCString(str); MAPI_TRACE2( "depth=%d, filePath=%s\n", pFolder->GetDepth(), ansiStr); NS_Free(ansiStr); #endif } MAPI_TRACE0( "---------------------------------------------\n"); }
BOOL CMapiApi::LogOn( void) { if (!m_initialized) { MAPI_TRACE0( "Tried to LogOn before initializing MAPI\n"); return( FALSE); } if (m_lpSession) return( TRUE); HRESULT hr; hr = MAPILogonEx( 0, // might need to be passed in HWND NULL, // profile name, 64 char max (LPTSTR) NULL, // profile password, 64 char max (LPTSTR) // MAPI_NEW_SESSION | MAPI_NO_MAIL | MAPI_LOGON_UI | MAPI_EXPLICIT_PROFILE, // MAPI_NEW_SESSION | MAPI_NO_MAIL | MAPI_LOGON_UI, // MAPI_NO_MAIL | MAPI_LOGON_UI, MAPI_NO_MAIL | MAPI_USE_DEFAULT | MAPI_EXTENDED | MAPI_NEW_SESSION, &m_lpSession); if (FAILED(hr)) { m_lpSession = NULL; MAPI_TRACE2( "LogOn failed: 0x%lx, %d\n", (long)hr, (int)hr); return( FALSE); } MAPI_TRACE0( "MAPI Logged on\n"); return( TRUE); }
bool CMapiMessage::CopyBinAttachToFile(LPATTACH lpAttach, nsIFile **tmp_file) { nsCOMPtr<nsIFile> _tmp_file; nsresult rv = GetSpecialDirectoryWithFileName(NS_OS_TEMP_DIR, "mapiattach.tmp", getter_AddRefs(_tmp_file)); NS_ENSURE_SUCCESS(rv, false); rv = _tmp_file->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 00600); NS_ENSURE_SUCCESS(rv, false); nsCString tmpPath; _tmp_file->GetNativePath(tmpPath); LPSTREAM lpStreamFile; HRESULT hr = CMapiApi::OpenStreamOnFile(gpMapiAllocateBuffer, gpMapiFreeBuffer, STGM_READWRITE | STGM_CREATE, const_cast<char*>(tmpPath.get()), NULL, &lpStreamFile); if (HR_FAILED(hr)) { MAPI_TRACE1("~~ERROR~~ OpenStreamOnFile failed - temp path: %s\r\n", tmpPath.get()); return false; } bool bResult = true; LPSTREAM lpAttachStream; hr = lpAttach->OpenProperty(PR_ATTACH_DATA_BIN, &IID_IStream, 0, 0, (LPUNKNOWN *)&lpAttachStream); if (HR_FAILED(hr)) { MAPI_TRACE0("~~ERROR~~ OpenProperty failed for PR_ATTACH_DATA_BIN.\r\n"); lpAttachStream = NULL; bResult = false; } else { STATSTG st; hr = lpAttachStream->Stat(&st, STATFLAG_NONAME); if (HR_FAILED(hr)) { MAPI_TRACE0("~~ERROR~~ Stat failed for attachment stream\r\n"); bResult = false; } else { hr = lpAttachStream->CopyTo(lpStreamFile, st.cbSize, NULL, NULL); if (HR_FAILED(hr)) { MAPI_TRACE0("~~ERROR~~ Attach Stream CopyTo temp file failed.\r\n"); bResult = false; } } } if (lpAttachStream) lpAttachStream->Release(); lpStreamFile->Release(); if (!bResult) _tmp_file->Remove(false); else CallQueryInterface(_tmp_file, tmp_file); return bResult; }
BOOL CMapiFolderContents::SetUpIter( void) { // First, open up the MAPIFOLDER object ULONG ulObjType; HRESULT hr; hr = m_lpMdb->OpenEntry( m_fCbEid, (LPENTRYID) m_fLpEid, NULL, 0, &ulObjType, (LPUNKNOWN *) &m_lpFolder); if (FAILED(hr) || !m_lpFolder) { m_lpFolder = NULL; m_lastError = hr; MAPI_TRACE2( "CMapiFolderContents OpenEntry failed: 0x%lx, %d\n", (long)hr, (int)hr); return( FALSE); } if (ulObjType != MAPI_FOLDER) { m_lastError = -1; MAPI_TRACE0( "CMapiFolderContents - bad object type, not a folder.\n"); return( FALSE); } hr = m_lpFolder->GetContentsTable( 0, &m_lpTable); if (FAILED(hr) || !m_lpTable) { m_lastError = hr; m_lpTable = NULL; MAPI_TRACE2( "CMapiFolderContents - GetContentsTable failed: 0x%lx, %d\n", (long)hr, (int)hr); return( FALSE); } hr = m_lpTable->GetRowCount( 0, &m_count); if (FAILED(hr)) { m_lastError = hr; MAPI_TRACE0( "CMapiFolderContents - GetRowCount failed\n"); return( FALSE); } hr = m_lpTable->SetColumns( (LPSPropTagArray)&ptaEid, 0); if (FAILED(hr)) { m_lastError = hr; MAPI_TRACE2( "CMapiFolderContents - SetColumns failed: 0x%lx, %d\n", (long)hr, (int)hr); return( FALSE); } hr = m_lpTable->SeekRow( BOOKMARK_BEGINNING, 0, NULL); if (FAILED(hr)) { m_lastError = hr; MAPI_TRACE2( "CMapiFolderContents - SeekRow failed: 0x%lx, %d\n", (long)hr, (int)hr); return( FALSE); } return( TRUE); }
BOOL CMapiApi::GetStoreFolders( ULONG cbEid, LPENTRYID lpEid, CMapiFolderList& folders, int startDepth) { // Fill in the array with the folders in the given store if (!m_initialized || !m_lpSession) { MAPI_TRACE0( "MAPI not initialized for GetStoreFolders\n"); return( FALSE); } m_lpMdb = NULL; CMsgStore * pStore = FindMessageStore( cbEid, lpEid); BOOL bResult = FALSE; LPSPropValue pVal; if (pStore && pStore->Open( m_lpSession, &m_lpMdb)) { // Successful open, do the iteration of the store pVal = GetMapiProperty( m_lpMdb, PR_IPM_SUBTREE_ENTRYID); if (pVal) { ULONG cbEntry; LPENTRYID pEntry; LPMAPIFOLDER lpSubTree = NULL; if (GetEntryIdFromProp( pVal, cbEntry, pEntry)) { // Open up the folder! bResult = OpenEntry( cbEntry, pEntry, (LPUNKNOWN *)&lpSubTree); MAPIFreeBuffer( pEntry); if (bResult && lpSubTree) { // Iterate the subtree with the results going into the folder list CGetStoreFoldersIter iterHandler( this, folders, startDepth); bResult = IterateHierarchy( &iterHandler, lpSubTree); lpSubTree->Release(); } else { MAPI_TRACE0( "GetStoreFolders: Error opening sub tree.\n"); } } else { MAPI_TRACE0( "GetStoreFolders: Error getting entryID from sub tree property val.\n"); } } else { MAPI_TRACE0( "GetStoreFolders: Error getting sub tree property.\n"); } } else { MAPI_TRACE0( "GetStoreFolders: Error opening message store.\n"); } return( bResult); }
BOOL CMapiApi::GetStringFromProp( LPSPropValue pVal, nsString& val, BOOL delVal) { BOOL bResult = TRUE; if ( pVal && (PROP_TYPE( pVal->ulPropTag) == PT_STRING8)) { CStrToUnicode( (const char *)pVal->Value.lpszA, val); } else if ( pVal && (PROP_TYPE( pVal->ulPropTag) == PT_UNICODE)) { val = (PRUnichar *) pVal->Value.lpszW; } else if (pVal && (PROP_TYPE( pVal->ulPropTag) == PT_NULL)) { val.Truncate(); } else if (pVal && (PROP_TYPE( pVal->ulPropTag) == PT_ERROR)) { val.Truncate(); bResult = FALSE; } else { if (pVal) { MAPI_TRACE1( "GetStringFromProp: invalid value, expecting string - %d\n", (int) PROP_TYPE( pVal->ulPropTag)); } else { MAPI_TRACE0( "GetStringFromProp: invalid value, expecting string, got null pointer\n"); } val.Truncate(); bResult = FALSE; } if (pVal && delVal) MAPIFreeBuffer( pVal); return( bResult); }
BOOL CMapiApi::HandleContentsItem( ULONG oType, ULONG cb, LPENTRYID pEntry) { if (oType == MAPI_MESSAGE) { LPMESSAGE pMsg; if (OpenEntry( cb, pEntry, (LPUNKNOWN *) &pMsg)) { LPSPropValue pVal; pVal = GetMapiProperty( pMsg, PR_SUBJECT); ReportStringProp( "PR_SUBJECT:", pVal); pVal = GetMapiProperty( pMsg, PR_DISPLAY_BCC); ReportStringProp( "PR_DISPLAY_BCC:", pVal); pVal = GetMapiProperty( pMsg, PR_DISPLAY_CC); ReportStringProp( "PR_DISPLAY_CC:", pVal); pVal = GetMapiProperty( pMsg, PR_DISPLAY_TO); ReportStringProp( "PR_DISPLAY_TO:", pVal); pVal = GetMapiProperty( pMsg, PR_MESSAGE_CLASS); ReportStringProp( "PR_MESSAGE_CLASS:", pVal); ListProperties( pMsg); pMsg->Release(); } else { MAPI_TRACE0( " Folder type - error opening\n"); } } else MAPI_TRACE1( " ObjectType: %ld\n", oType); return( TRUE); }
CMsgStore * CMapiApi::FindMessageStore( ULONG cbEid, LPENTRYID lpEid) { if (!m_lpSession) { MAPI_TRACE0( "FindMessageStore called before session is open\n"); m_lastError = -1; return( NULL); } ULONG result; HRESULT hr; CMsgStore * pStore; for (int i = 0; i < m_pStores->Count(); i++) { pStore = (CMsgStore *) m_pStores->ElementAt( i); hr = m_lpSession->CompareEntryIDs( cbEid, lpEid, pStore->GetCBEntryID(), pStore->GetLPEntryID(), 0, &result); if (HR_FAILED( hr)) { MAPI_TRACE2( "CompareEntryIDs failed: 0x%lx, %d\n", (long)hr, (int)hr); m_lastError = hr; return( NULL); } if ( result) { return( pStore); } } pStore = new CMsgStore( cbEid, lpEid); AddMessageStore( pStore); return( pStore); }
void CMapiApi::ListProperties( LPMAPIPROP lpProp, BOOL getValues) { LPSPropTagArray pArray; HRESULT hr = lpProp->GetPropList( 0, &pArray); if (FAILED(hr)) { MAPI_TRACE0( " Unable to retrieve property list\n"); return; } ULONG count = 0; LPMAPINAMEID FAR * lppPropNames; SPropTagArray tagArray; LPSPropTagArray lpTagArray = &tagArray; tagArray.cValues = (ULONG)1; nsCString desc; for (ULONG i = 0; i < pArray->cValues; i++) { GetPropTagName( pArray->aulPropTag[i], desc); if (getValues) { tagArray.aulPropTag[0] = pArray->aulPropTag[i]; hr = lpProp->GetNamesFromIDs(&lpTagArray, nsnull, 0, &count, &lppPropNames); if (hr == S_OK) MAPIFreeBuffer(lppPropNames); LPSPropValue pVal = GetMapiProperty( lpProp, pArray->aulPropTag[i]); if (pVal) { desc += ", "; ListPropertyValue( pVal, desc); MAPIFreeBuffer( pVal); } } MAPI_TRACE2( " Tag #%d: %s\n", (int)i, (const char *)desc); } MAPIFreeBuffer( pArray); }
BOOL CMapiApi::OpenEntry( ULONG cbEntry, LPENTRYID pEntryId, LPUNKNOWN *ppOpen) { if (!m_lpMdb) { MAPI_TRACE0( "OpenEntry called before the message store is open\n"); return( FALSE); } return( OpenMdbEntry( m_lpMdb, cbEntry, pEntryId, ppOpen)); }
BOOL CMapiApi::OpenStore( ULONG cbEid, LPENTRYID lpEid, LPMDB *ppMdb) { if (!m_lpSession) { MAPI_TRACE0( "OpenStore called before a session was opened\n"); return( FALSE); } CMsgStore * pStore = FindMessageStore( cbEid, lpEid); if (pStore && pStore->Open( m_lpSession, ppMdb)) return( TRUE); return( FALSE); }
LONG CMapiApi::GetLongFromProp( LPSPropValue pVal, BOOL delVal) { LONG val = 0; if ( pVal && (PROP_TYPE( pVal->ulPropTag) == PT_LONG)) { val = pVal->Value.l; } else if (pVal && (PROP_TYPE( pVal->ulPropTag) == PT_NULL)) { val = 0; } else if (pVal && (PROP_TYPE( pVal->ulPropTag) == PT_ERROR)) { val = 0; MAPI_TRACE0( "GetLongFromProp: Error retrieving property\n"); } else { MAPI_TRACE0( "GetLongFromProp: invalid value, expecting long\n"); } if (pVal && delVal) MAPIFreeBuffer( pVal); return( val); }
BOOL CMapiMessage::FetchHeaders( void) { LPSPropValue pVal = CMapiApi::GetMapiProperty( m_lpMsg, PR_TRANSPORT_MESSAGE_HEADERS); if (pVal && CMapiApi::IsLargeProperty( pVal)) { m_headers.Truncate(); CMapiApi::GetLargeStringProperty( m_lpMsg, PR_TRANSPORT_MESSAGE_HEADERS, m_headers); } else if (pVal && (PROP_TYPE( pVal->ulPropTag) == PT_TSTRING) && (pVal->Value.LPSZ) && (*(pVal->Value.LPSZ))) { m_headers = pVal->Value.LPSZ; } else { // Need to build the headers from the other stuff m_headers.Truncate(); BuildHeaders(); } if (pVal) CMapiApi::MAPIFreeBuffer( pVal); m_fromLine.Truncate(); if (NeedsFromLine()) { BuildFromLine(); } if (!m_fromLine.IsEmpty()) { MAPI_DUMP_STRING(m_fromLine.get()); } MAPI_DUMP_STRING(m_headers.get()); MAPI_TRACE0("\r\n"); ProcessHeaders(); if (!m_headers.IsEmpty()) { if (!m_bHasSubject) AddSubject( m_headers); if (!m_bHasFrom) AddFrom( m_headers); if (!m_bHasDate) AddDate( m_headers); m_headers.Trim( kWhitespace, PR_FALSE, PR_TRUE); m_headers += "\x0D\x0A"; } return( !m_headers.IsEmpty()); }
BOOL CMapiApi::Initialize( void) { if (m_initialized) return( TRUE); HRESULT hr; hr = MAPIInitialize( NULL); if (FAILED(hr)) { MAPI_TRACE2( "MAPI Initialize failed: 0x%lx, %d\n", (long)hr, (int)hr); return( FALSE); } m_initialized = TRUE; MAPI_TRACE0( "MAPI Initialized\n"); return( TRUE); }
BOOL CMapiApi::HandleHierarchyItem( ULONG oType, ULONG cb, LPENTRYID pEntry) { if (oType == MAPI_FOLDER) { LPMAPIFOLDER pFolder; if (OpenEntry( cb, pEntry, (LPUNKNOWN *) &pFolder)) { LPSPropValue pVal; pVal = GetMapiProperty( pFolder, PR_DISPLAY_NAME); ReportStringProp( "Folder name:", pVal); IterateContents( NULL, pFolder); IterateHierarchy( NULL, pFolder); pFolder->Release(); } else { MAPI_TRACE0( " Folder type - error opening\n"); } } else MAPI_TRACE1( " ObjectType: %ld\n", oType); return( TRUE); }
BOOL CMapiMessage::FetchBody( void) { m_bodyIsHtml = FALSE; m_body.Truncate(); // Is it html? LPSPropValue pVal = CMapiApi::GetMapiProperty( m_lpMsg, 0x1013001e); if (pVal && CMapiApi::IsLargeProperty( pVal)) CMapiApi::GetLargeStringProperty( m_lpMsg, 0x1013001e, m_body); else if (pVal && (PROP_TYPE( pVal->ulPropTag) == PT_TSTRING) && (pVal->Value.LPSZ) && (*(pVal->Value.LPSZ))) m_body = pVal->Value.LPSZ; // kind-hearted Outlook will give us html even for a plain text message. But it will include // a comment saying it did the conversion. We'll use this as a hack to really use // the plain text part. if (!m_body.IsEmpty() && m_body.Find("<!-- Converted from text/plain format -->") == kNotFound) m_bodyIsHtml = TRUE; else { pVal = CMapiApi::GetMapiProperty( m_lpMsg, PR_BODY); if (pVal) { if (pVal && CMapiApi::IsLargeProperty( pVal)) { CMapiApi::GetLargeStringProperty( m_lpMsg, PR_BODY, m_body); } else { if (pVal && (PROP_TYPE( pVal->ulPropTag) == PT_TSTRING) && (pVal->Value.LPSZ) && (*(pVal->Value.LPSZ))) { m_body = pVal->Value.LPSZ; } } } } if (pVal) CMapiApi::MAPIFreeBuffer( pVal); MAPI_DUMP_STRING(m_body.get()); MAPI_TRACE0("\r\n"); return( TRUE); }
BOOL CGetStoreFoldersIter::HandleHierarchyItem( ULONG oType, ULONG cb, LPENTRYID pEntry) { if (oType == MAPI_FOLDER) { LPMAPIFOLDER pFolder; if (m_pApi->OpenEntry( cb, pEntry, (LPUNKNOWN *) &pFolder)) { LPSPropValue pVal; nsString name; pVal = m_pApi->GetMapiProperty( pFolder, PR_CONTAINER_CLASS); if (pVal) m_pApi->GetStringFromProp( pVal, name); else name.Truncate(); if ((name.IsEmpty() && m_isMail) || (!ExcludeFolderClass(name.get()))) { pVal = m_pApi->GetMapiProperty( pFolder, PR_DISPLAY_NAME); m_pApi->GetStringFromProp( pVal, name); CMapiFolder *pNewFolder = new CMapiFolder(name.get(), cb, pEntry, m_depth); m_pList->AddItem( pNewFolder); pVal = m_pApi->GetMapiProperty( pFolder, PR_FOLDER_TYPE); MAPI_TRACE2( "Type: %d, name: %s\n", m_pApi->GetLongFromProp( pVal), (const char *)name); // m_pApi->ListProperties( pFolder); CGetStoreFoldersIter nextIter( m_pApi, *m_pList, m_depth + 1, m_isMail); m_pApi->IterateHierarchy( &nextIter, pFolder); } pFolder->Release(); } else { MAPI_TRACE0( "GetStoreFolders - HandleHierarchyItem: Error opening folder entry.\n"); return( FALSE); } } else MAPI_TRACE1( "GetStoreFolders - HandleHierarchyItem: Unhandled ObjectType: %ld\n", oType); return( TRUE); }
// If the value is a string, get it... BOOL CMapiApi::GetEntryIdFromProp( LPSPropValue pVal, ULONG& cbEntryId, LPENTRYID& lpEntryId, BOOL delVal) { if (!pVal) return( FALSE); BOOL bResult = TRUE; switch( PROP_TYPE( pVal->ulPropTag)) { case PT_BINARY: cbEntryId = pVal->Value.bin.cb; MAPIAllocateBuffer( cbEntryId, (LPVOID *) &lpEntryId); memcpy( lpEntryId, pVal->Value.bin.lpb, cbEntryId); break; default: MAPI_TRACE0( "EntryId not in BINARY prop value\n"); bResult = FALSE; break; } if (pVal && delVal) MAPIFreeBuffer( pVal); return( bResult); }
BOOL CMapiApi::IterateStores( CMapiFolderList& stores) { stores.ClearAll(); if (!m_lpSession) { MAPI_TRACE0( "IterateStores called before session is open\n"); m_lastError = -1; return( FALSE); } HRESULT hr; /* -- Some Microsoft sample code just to see if things are working --- *//* ULONG cbEIDStore; LPENTRYID lpEIDStore; hr = HrMAPIFindDefaultMsgStore( m_lpSession, &cbEIDStore, &lpEIDStore); if (HR_FAILED(hr)) { MAPI_TRACE0( "Default message store not found\n"); // MessageBox(NULL,"Message Store Not Found",NULL,MB_OK); } else { LPMDB lpStore; MAPI_TRACE0( "Default Message store FOUND\n"); hr = m_lpSession->OpenMsgStore( NULL, cbEIDStore, lpEIDStore, NULL, MDB_NO_MAIL | MDB_NO_DIALOG, &lpStore); if (HR_FAILED(hr)) { MAPI_TRACE1( "Unable to open default message store: 0x%lx\n", hr); } else { MAPI_TRACE0( "Default message store OPENED\n"); lpStore->Release(); } } */ LPMAPITABLE lpTable; hr = m_lpSession->GetMsgStoresTable( 0, &lpTable); if (FAILED(hr)) { MAPI_TRACE0( "GetMsgStoresTable failed\n"); m_lastError = hr; return( FALSE); } ULONG rowCount; hr = lpTable->GetRowCount( 0, &rowCount); MAPI_TRACE1( "MsgStores Table rowCount: %ld\n", rowCount); hr = lpTable->SetColumns( (LPSPropTagArray)&ptaTbl, 0); if (FAILED(hr)) { lpTable->Release(); MAPI_TRACE2( "SetColumns failed: 0x%lx, %d\n", (long)hr, (int)hr); m_lastError = hr; return( FALSE); } hr = lpTable->SeekRow( BOOKMARK_BEGINNING, 0, NULL); if (FAILED(hr)) { lpTable->Release(); MAPI_TRACE2( "SeekRow failed: 0x%lx, %d\n", (long)hr, (int)hr); m_lastError = hr; return( FALSE); } int cNumRows = 0; LPSRowSet lpRow; BOOL keepGoing = TRUE; BOOL bResult = TRUE; do { lpRow = NULL; hr = lpTable->QueryRows( 1, 0, &lpRow); if(HR_FAILED(hr)) { MAPI_TRACE2( "QueryRows failed: 0x%lx, %d\n", (long)hr, (int)hr); bResult = FALSE; m_lastError = hr; break; } if(lpRow) { cNumRows = lpRow->cRows; if (cNumRows) { LPCTSTR lpStr = (LPCTSTR) lpRow->aRow[0].lpProps[itblPR_DISPLAY_NAME].Value.LPSZ; LPENTRYID lpEID = (LPENTRYID) lpRow->aRow[0].lpProps[itblPR_ENTRYID].Value.bin.lpb; ULONG cbEID = lpRow->aRow[0].lpProps[itblPR_ENTRYID].Value.bin.cb; // In the future, GetStoreInfo needs to somehow return // whether or not the store is from an IMAP server. // Currently, GetStoreInfo opens the store and attempts // to get the hierarchy tree. If the tree is empty or // does not exist, then szContents will be zero. We'll // assume that any store that doesn't have anything in // it's hierarchy tree is not a store we want to import - // there would be nothing to import from anyway! // Currently, this does exclude IMAP server accounts // which is the desired behaviour. int strLen = strlen(lpStr); PRUnichar * pwszStr = (PRUnichar *) nsMemory::Alloc((strLen + 1) * sizeof(WCHAR)); if (!pwszStr) { // out of memory FreeProws( lpRow); lpTable->Release(); return FALSE; } ::MultiByteToWideChar(CP_ACP, 0, lpStr, strlen(lpStr) + 1, pwszStr, (strLen + 1) * sizeof(WCHAR)); CMapiFolder *pFolder = new CMapiFolder( pwszStr, cbEID, lpEID, 0, MAPI_STORE); nsMemory::Free(pwszStr); long szContents = 1; GetStoreInfo( pFolder, &szContents); MAPI_TRACE1( " DisplayName: %s\n", lpStr); if (szContents) { stores.AddItem( pFolder); } else { delete pFolder; MAPI_TRACE0( " ^^^^^ Not added to store list\n"); } keepGoing = TRUE; } FreeProws( lpRow); } } while ( SUCCEEDED(hr) && cNumRows && lpRow && keepGoing); lpTable->Release(); return( bResult); }
bool CMapiMessage::AddAttachment(DWORD aNum) { LPATTACH lpAttach = NULL; HRESULT hr = m_lpMsg->OpenAttach(aNum, NULL, 0, &lpAttach); if (HR_FAILED(hr)) { MAPI_TRACE2("\t\t****Attachment error, unable to open attachment: %d, 0x%lx\r\n", idx, hr); return false; } bool bResult = false; attach_data *data = new attach_data; ULONG aMethod; if (data) { bResult = true; // 1. Get the file that contains the attachment data LPSPropValue pVal = CMapiApi::GetMapiProperty(lpAttach, PR_ATTACH_METHOD); if (pVal) { aMethod = CMapiApi::GetLongFromProp(pVal); switch (aMethod) { case ATTACH_BY_VALUE: MAPI_TRACE1("\t\t** Attachment #%d by value.\r\n", aNum); bResult = CopyBinAttachToFile(lpAttach, getter_AddRefs(data->tmp_file)); data->delete_file = true; break; case ATTACH_BY_REFERENCE: case ATTACH_BY_REF_RESOLVE: case ATTACH_BY_REF_ONLY: pVal = CMapiApi::GetMapiProperty(lpAttach, PR_ATTACH_PATHNAME_W); if (pVal) { nsCString path; CMapiApi::GetStringFromProp(pVal, path); nsresult rv; data->tmp_file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv); if (NS_FAILED(rv) || !data->tmp_file) { MAPI_TRACE0("*** Error creating file spec for attachment\n"); bResult = false; } else data->tmp_file->InitWithNativePath(path); } MAPI_TRACE2("\t\t** Attachment #%d by ref: %s\r\n", aNum, m_attachPath.get()); break; case ATTACH_EMBEDDED_MSG: MAPI_TRACE1("\t\t** Attachment #%d by Embedded Message??\r\n", aNum); // Convert the embedded IMessage from PR_ATTACH_DATA_OBJ to rfc822 attachment // (see http://msdn.microsoft.com/en-us/library/cc842329.aspx) // This is a recursive call. bResult = CopyMsgAttachToFile(lpAttach, getter_AddRefs(data->tmp_file)); data->delete_file = true; break; case ATTACH_OLE: MAPI_TRACE1("\t\t** Attachment #%d by OLE - yuck!!!\r\n", aNum); break; default: MAPI_TRACE2("\t\t** Attachment #%d unknown attachment method - 0x%lx\r\n", aNum, aMethod); bResult = false; } } else bResult = false; if (bResult) bResult = data->tmp_file; if (bResult) { bool isFile = false; bool exists = false; data->tmp_file->Exists(&exists); data->tmp_file->IsFile(&isFile); if (!exists || !isFile) { bResult = false; MAPI_TRACE0("Attachment file does not exist\n"); } } if (bResult) bResult = GetURL(data->tmp_file, getter_AddRefs(data->orig_url)); if (bResult) { // Now we have the file; proceed to the other properties data->encoding = NS_strdup(ENCODING_BINARY); nsString fname, fext; pVal = CMapiApi::GetMapiProperty(lpAttach, PR_ATTACH_LONG_FILENAME_W); if (!pVal) pVal = CMapiApi::GetMapiProperty(lpAttach, PR_ATTACH_FILENAME_W); CMapiApi::GetStringFromProp(pVal, fname); pVal = CMapiApi::GetMapiProperty(lpAttach, PR_ATTACH_EXTENSION_W); CMapiApi::GetStringFromProp(pVal, fext); MAPI_TRACE2("\t\t\t--- File name: %s, extension: %s\r\n", fname.get(), fext.get()); if (fext.IsEmpty()) { int idx = fname.RFindChar(L'.'); if (idx != -1) fext = Substring(fname, idx); } else if (fname.RFindChar(L'.') == -1) { fname += L"."; fname += fext; } if (fname.IsEmpty()) { // If no description use "Attachment i" format. fname = L"Attachment "; fname.AppendInt(static_cast<uint32_t>(aNum)); } data->real_name = ToNewUTF8String(fname); nsCString tmp; // We have converted it to the rfc822 document if (aMethod == ATTACH_EMBEDDED_MSG) { data->type = NS_strdup(MESSAGE_RFC822); } else { pVal = CMapiApi::GetMapiProperty(lpAttach, PR_ATTACH_MIME_TAG_A); CMapiApi::GetStringFromProp(pVal, tmp); MAPI_TRACE1("\t\t\t--- Mime type: %s\r\n", tmp.get()); if (tmp.IsEmpty()) { uint8_t *pType = NULL; if (!fext.IsEmpty()) { pType = CMimeTypes::GetMimeType(fext); } if (pType) data->type = NS_strdup((PC_S8)pType); else data->type = NS_strdup(APPLICATION_OCTET_STREAM); } else data->type = ToNewCString(tmp); } pVal = CMapiApi::GetMapiProperty(lpAttach, PR_ATTACH_CONTENT_ID_A); CMapiApi::GetStringFromProp(pVal, tmp); if (!tmp.IsEmpty()) data->cid = ToNewCString(tmp); } if (bResult) { // Now we need to decide if this attachment is embedded or not. // At first, I tried to simply check for the presence of the Content-Id. // But it turned out that this method is unreliable, since there exist cases // when an attachment has a Content-Id while isn't embedded (even in a message // with a plain-text body!). So next I tried to look for <img> tags that contain // the found Content-Id. But this is unreliable, too, because there exist cases // where other places of HTML reference the embedded messages (e.g. it may be // a background of a table cell, or some CSS; further, it is possible that the // reference to an embedded object is not in the main body, but in another // embedded object - like body references a CSS attachment that in turn references // a picture as a background of its element). From the other hand, it's unreliable // to relax the search criteria to any occurence of the Content-Id string in the body - // partly because the string may be simply in a text or other non-referencing part, // partly because of the abovementioned possibility that the reference is outside // the body at all. // There exist the PR_ATTACH_FLAGS property of the attachment. The MS documentation // tells about two possible flags in it: ATT_INVISIBLE_IN_HTML and ATT_INVISIBLE_IN_RTF. // There is at least one more undocumented flag: ATT_MHTML_REF. Some sources in Internet // suggest simply check for the latter flag to distinguish between the embedded // and ordinary attachments. But my observations indicate that even if the flags // don't include ATT_MHTML_REF, the attachment is still may be embedded. // However, my observations always show that the message is embedded if the flags // is not 0. // So now I will simply test for the non-zero flags to decide whether the attachment // is embedded or not. Possible advantage is reliability (I hope). // Another advantage is that it's much faster than search the body for Content-Id. DWORD flags = 0; pVal = CMapiApi::GetMapiProperty(lpAttach, PR_ATTACH_FLAGS); if (pVal) flags = CMapiApi::GetLongFromProp(pVal); if (m_bodyIsHtml && data->cid && (flags != 0)) // this is the embedded attachment m_embattachments.push_back(data); else // this is ordinary attachment m_stdattachments.push_back(data); } else { delete data; } } lpAttach->Release(); return bResult; }
BOOL CMapiApi::IterateContents( CMapiContentIter *pIter, LPMAPIFOLDER pFolder, ULONG flags) { // flags can be 0 or MAPI_ASSOCIATED // MAPI_ASSOCIATED is usually used for forms and views HRESULT hr; LPMAPITABLE lpTable; hr = pFolder->GetContentsTable( flags, &lpTable); if (FAILED(hr)) { MAPI_TRACE2( "GetContentsTable failed: 0x%lx, %d\n", (long)hr, (int)hr); return( FALSE); } ULONG rowCount; hr = lpTable->GetRowCount( 0, &rowCount); if (!rowCount) { MAPI_TRACE0( " Empty Table\n"); } hr = lpTable->SetColumns( (LPSPropTagArray)&ptaEid, 0); if (FAILED(hr)) { lpTable->Release(); MAPI_TRACE2( "SetColumns failed: 0x%lx, %d\n", (long)hr, (int)hr); return( FALSE); } hr = lpTable->SeekRow( BOOKMARK_BEGINNING, 0, NULL); if (FAILED(hr)) { lpTable->Release(); MAPI_TRACE2( "SeekRow failed: 0x%lx, %d\n", (long)hr, (int)hr); return( FALSE); } int cNumRows = 0; LPSRowSet lpRow; BOOL keepGoing = TRUE; BOOL bResult = TRUE; do { lpRow = NULL; hr = lpTable->QueryRows( 1, 0, &lpRow); if(HR_FAILED(hr)) { MAPI_TRACE2( "QueryRows failed: 0x%lx, %d\n", (long)hr, (int)hr); bResult = FALSE; break; } if(lpRow) { cNumRows = lpRow->cRows; if (cNumRows) { LPENTRYID lpEID = (LPENTRYID) lpRow->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.lpb; ULONG cbEID = lpRow->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.cb; ULONG oType = lpRow->aRow[0].lpProps[ieidPR_OBJECT_TYPE].Value.ul; keepGoing = HandleContentsItem( oType, cbEID, lpEID); MAPI_TRACE1( " ObjectType: %ld\n", oType); } FreeProws( lpRow); } } while ( SUCCEEDED(hr) && cNumRows && lpRow && keepGoing); lpTable->Release(); return( bResult); }
BOOL CMapiMessage::CopyBinAttachToFile( LPATTACH lpAttach) { LPSTREAM lpStreamFile; m_ownsAttachFile = FALSE; m_attachPath.Truncate(); nsCOMPtr<nsIFile> tmpFile; nsresult rv = GetSpecialDirectoryWithFileName(NS_OS_TEMP_DIR, "mapiattach.tmp", getter_AddRefs(tmpFile)); NS_ENSURE_SUCCESS(rv, rv); rv = tmpFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 00600); NS_ENSURE_SUCCESS(rv, rv); nsCString tmpPath; tmpFile->GetNativePath(tmpPath); HRESULT hr = CMapiApi::OpenStreamOnFile( gpMapiAllocateBuffer, gpMapiFreeBuffer, STGM_READWRITE | STGM_CREATE, (char *) tmpPath.get(), NULL, &lpStreamFile); if (HR_FAILED(hr)) { MAPI_TRACE1("~~ERROR~~ OpenStreamOnFile failed - temp path: %s\r\n", tmpPath.get()); return( FALSE); } MAPI_TRACE1("\t\t** Attachment extracted to temp file: %s\r\n", m_attachPath.get()); BOOL bResult = TRUE; LPSTREAM lpAttachStream; hr = lpAttach->OpenProperty( PR_ATTACH_DATA_BIN, &IID_IStream, 0, 0, (LPUNKNOWN *)&lpAttachStream); if (HR_FAILED( hr)) { MAPI_TRACE0( "~~ERROR~~ OpenProperty failed for PR_ATTACH_DATA_BIN.\r\n"); lpAttachStream = NULL; bResult = FALSE; } else { STATSTG st; hr = lpAttachStream->Stat( &st, STATFLAG_NONAME); if (HR_FAILED( hr)) { MAPI_TRACE0( "~~ERROR~~ Stat failed for attachment stream\r\n"); bResult = FALSE; } else { hr = lpAttachStream->CopyTo( lpStreamFile, st.cbSize, NULL, NULL); if (HR_FAILED( hr)) { MAPI_TRACE0( "~~ERROR~~ Attach Stream CopyTo temp file failed.\r\n"); bResult = FALSE; } } } m_attachPath = tmpPath; if (lpAttachStream) lpAttachStream->Release(); lpStreamFile->Release(); if (!bResult) tmpFile->Remove(PR_FALSE); else m_ownsAttachFile = TRUE; return( bResult); }
bool CMapiMessage::FetchBody(void) { m_bodyIsHtml = false; m_body.Truncate(); // Get the Outlook codepage info; if unsuccessful then it defaults to 0 (CP_ACP) -> system default // Maybe we can use this info later? unsigned int codepage=0; LPSPropValue pVal = CMapiApi::GetMapiProperty(m_lpMsg, PR_INTERNET_CPID); if (pVal) { if (PROP_TYPE(pVal->ulPropTag) == PT_LONG) codepage = pVal->Value.l; CMapiApi::MAPIFreeBuffer(pVal); } unsigned long nativeBodyType = 0; if (CMapiApi::GetRTFPropertyDecodedAsUTF16(m_lpMsg, m_body, nativeBodyType, codepage)) { m_bodyIsHtml = nativeBodyType == MAPI_NATIVE_BODY_TYPE_HTML; } else { // Cannot get RTF version // Is it html? pVal = CMapiApi::GetMapiProperty(m_lpMsg, PR_BODY_HTML_W); if (pVal) { if (CMapiApi::IsLargeProperty(pVal)) CMapiApi::GetLargeStringProperty(m_lpMsg, PR_BODY_HTML_W, m_body); else if ((PROP_TYPE(pVal->ulPropTag) == PT_UNICODE) && (pVal->Value.lpszW) && (*(pVal->Value.lpszW))) m_body.Assign(pVal->Value.lpszW); CMapiApi::MAPIFreeBuffer(pVal); } // Kind-hearted Outlook will give us html even for a plain text message. // But it will include a comment saying it did the conversion. // We'll use this as a hack to really use the plain text part. // // Sadly there are cases where this string is returned despite the fact // that the message is indeed HTML. // // To detect the "true" plain text messages, we look for our string // immediately following the <BODY> tag. if (!m_body.IsEmpty() && m_body.Find("<BODY>\r\n<!-- Converted from text/plain format -->") == kNotFound) { m_bodyIsHtml = true; } else { pVal = CMapiApi::GetMapiProperty(m_lpMsg, PR_BODY_W); if (pVal) { if (CMapiApi::IsLargeProperty(pVal)) CMapiApi::GetLargeStringProperty(m_lpMsg, PR_BODY_W, m_body); else if ((PROP_TYPE(pVal->ulPropTag) == PT_UNICODE) && (pVal->Value.lpszW) && (*(pVal->Value.lpszW))) m_body.Assign(pVal->Value.lpszW); CMapiApi::MAPIFreeBuffer(pVal); } } } // OK, now let's restore the original encoding! // 1. We may have a header defining the charset (we already called the FetchHeaders(), and there ProcessHeaders(); // in this case, the m_mimeCharset is set. See nsOutlookMail::ImportMailbox()) // 2. We may have the codepage walue provided by Outlook ("codepage" at the very beginning of this function) // 3. We may have an HTML charset header. bool bFoundCharset = false; if (!m_mimeCharset.IsEmpty()) // The top-level header data bFoundCharset = CheckBodyInCharsetRange(m_mimeCharset.get()); // No valid charset in the message header - try the HTML header. // arguably may be useless if (!bFoundCharset && m_bodyIsHtml) { ExtractMetaCharset(m_body.get(), m_body.Length(), m_mimeCharset); if (!m_mimeCharset.IsEmpty()) bFoundCharset = CheckBodyInCharsetRange(m_mimeCharset.get()); } // Get from Outlook (seems like it keeps the MIME part header encoding info) if (!bFoundCharset && codepage) { const char* charset = CpToCharset(codepage); if (charset) { bFoundCharset = CheckBodyInCharsetRange(charset); if (bFoundCharset) m_mimeCharset.Assign(charset); } } if (!bFoundCharset) { // Use system default const char* charset = nsMsgI18NFileSystemCharset(); if (charset) { bFoundCharset = CheckBodyInCharsetRange(charset); if (bFoundCharset) m_mimeCharset.Assign(charset); } } if (!bFoundCharset) // Everything else failed, let's use the lossless utf-8... m_mimeCharset.Assign("utf-8"); MAPI_DUMP_STRING(m_body.get()); MAPI_TRACE0("\r\n"); return true; }