// -------------------------------------------------------------------------------- // Mimeapi.cpp // Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved // Steven J. Bailey // -------------------------------------------------------------------------------- #include "pch.hxx" #include "dllmain.h" #include "olealloc.h" #include "partial.h" #include "smime.h" #include "vstream.h" #include "internat.h" #include "stackstr.h" #include "ixputil.h" #include "webdocs.h" #include "containx.h" #include "inetstm.h" #include "mhtmlurl.h" #include "booktree.h" #include "bookbody.h" #include #include #include "mlang.h" #include "strconst.h" #include "symcache.h" #include "mimeapi.h" #include "hash.h" #include "shared.h" #include "demand.h" // ------------------------------------------------------------------------------------------ // Special Partial Headers // ------------------------------------------------------------------------------------------ static LPCSTR g_rgszPartialPids[] = { PIDTOSTR(PID_HDR_CNTTYPE), PIDTOSTR(PID_HDR_CNTXFER), PIDTOSTR(PID_HDR_CNTDESC), PIDTOSTR(PID_HDR_MESSAGEID), PIDTOSTR(PID_HDR_MIMEVER), PIDTOSTR(PID_HDR_CNTID), PIDTOSTR(PID_HDR_CNTDISP), STR_HDR_ENCRYPTED }; // -------------------------------------------------------------------------------- // MimeGetAddressFormatW // -------------------------------------------------------------------------------- MIMEOLEAPI MimeGetAddressFormatW(REFIID riid, LPVOID pvObject, DWORD dwAdrType, ADDRESSFORMAT format, LPWSTR *ppszFormat) { // Locals HRESULT hr=S_OK; CMimePropertyContainer *pContainer=NULL; // Trace TraceCall("MimeGetAddressFormatW"); // Invalid Args if (NULL == pvObject) return(TraceResult(E_INVALIDARG)); // Is a messageW object ? if (IID_IMimeMessageW == riid) { // Get It CHECKHR(hr = ((IMimeMessageW *)pvObject)->GetAddressFormatW(dwAdrType, format, ppszFormat)); } // Is a message object ? else if (IID_IMimeMessage == riid) { // Query for IID_CMimePropertyContainer CHECKHR(hr = ((IMimeMessage *)pvObject)->BindToObject(HBODY_ROOT, IID_CMimePropertyContainer, (LPVOID *)&pContainer)); // Get the format CHECKHR(hr = pContainer->GetFormatW(dwAdrType, format, ppszFormat)); } // IID_IMimePropertySet else if (IID_IMimePropertySet == riid) { // Query for IID_CMimePropertyContainer CHECKHR(hr = ((IMimePropertySet *)pvObject)->QueryInterface(IID_CMimePropertyContainer, (LPVOID *)&pContainer)); // Get the format CHECKHR(hr = pContainer->GetFormatW(dwAdrType, format, ppszFormat)); } // IID_IMimeAddressTable else if (IID_IMimeAddressTable == riid) { // Query for IID_CMimePropertyContainer CHECKHR(hr = ((IMimeAddressTable *)pvObject)->QueryInterface(IID_CMimePropertyContainer, (LPVOID *)&pContainer)); // Get the format CHECKHR(hr = pContainer->GetFormatW(dwAdrType, format, ppszFormat)); } // IID_IMimeHeaderTable else if (IID_IMimeHeaderTable == riid) { // Query for IID_CMimePropertyContainer CHECKHR(hr = ((IMimeHeaderTable *)pvObject)->QueryInterface(IID_CMimePropertyContainer, (LPVOID *)&pContainer)); // Get the format CHECKHR(hr = pContainer->GetFormatW(dwAdrType, format, ppszFormat)); } // Final else { hr = TraceResult(E_NOINTERFACE); goto exit; } exit: // Cleanup SafeRelease(pContainer); // Done return(hr); } // -------------------------------------------------------------------------------- // MimeOleGetWindowsCP // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleSetCompatMode(DWORD dwMode) { // Add in the bit FLAGSET(g_dwCompatMode, dwMode); // Done return(S_OK); } // -------------------------------------------------------------------------------- // MimeOleGetWindowsCP // -------------------------------------------------------------------------------- CODEPAGEID MimeOleGetWindowsCP(HCHARSET hCharset) { // Locals INETCSETINFO rCharset; // Invalid Arg if (NULL == hCharset) return CP_ACP; // Loopup charset Assert(g_pInternat); if (FAILED(g_pInternat->GetCharsetInfo(hCharset, &rCharset))) return CP_ACP; // Return return MimeOleGetWindowsCPEx(&rCharset); } // -------------------------------------------------------------------------------- // MimeOleStripHeaders // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleStripHeaders(IMimeMessage *pMessage, HBODY hBody, LPCSTR pszNameDelete, LPCSTR pszHeaderAdd, IStream **ppStream) { // Locals HRESULT hr=S_OK; IMimeHeaderTable *pHdrTable=NULL; LPSTREAM pStmSource=NULL; LPSTREAM pStmDest=NULL; HHEADERROW hRow; HEADERROWINFO Info; DWORD cbLastRead=0; FINDHEADER Find={0}; ULARGE_INTEGER uliCopy; // Trace TraceCall("MimeOleStripHeaders"); // Invalid Arg if (NULL == pMessage || NULL == hBody || NULL == pszNameDelete || NULL == ppStream) return TraceResult(E_INVALIDARG); // Initialize *ppStream = NULL; // Get the message source, no commit IF_FAILEXIT(hr = pMessage->GetMessageSource(&pStmSource, 0)); // Get the Header Table for hBody IF_FAILEXIT(hr = pMessage->BindToObject(hBody, IID_IMimeHeaderTable, (LPVOID *)&pHdrTable)); // Initialize the Find Find.pszHeader = pszNameDelete; // Find this row IF_FAILEXIT(hr = pHdrTable->FindFirstRow(&Find, &hRow)); // Create a stream IF_FAILEXIT(hr = MimeOleCreateVirtualStream(&pStmDest)); // Delete this row while(1) { // Get the row information IF_FAILEXIT(hr = pHdrTable->GetRowInfo(hRow, &Info)); // Setup uliCopy uliCopy.QuadPart = Info.cboffStart - cbLastRead; // Seek IF_FAILEXIT(hr = HrStreamSeekSet(pStmSource, cbLastRead)); // Write from cbLast to Info.cboffStart IF_FAILEXIT(hr = HrCopyStreamCB(pStmSource, pStmDest, uliCopy, NULL, NULL)); // Set cbLast cbLastRead = Info.cboffEnd; // Find the next hr = pHdrTable->FindNextRow(&Find, &hRow); // Failure if (FAILED(hr)) { // MIME_E_NOT_FOUND if (MIME_E_NOT_FOUND == hr) { hr = S_OK; break; } else { TraceResult(hr); goto exit; } } } // Add on pszHeaderAdd if (pszHeaderAdd) { // Write the Add Header IF_FAILEXIT(hr = pStmDest->Write(pszHeaderAdd, lstrlen(pszHeaderAdd), NULL)); } // Write the Rest of pStmSource IF_FAILEXIT(hr = HrStreamSeekSet(pStmSource, cbLastRead)); // Write the Rest IF_FAILEXIT(hr = HrCopyStream(pStmSource, pStmDest, NULL)); // Commit IF_FAILEXIT(hr = pStmDest->Commit(STGC_DEFAULT)); // Rewind It IF_FAILEXIT(hr = HrRewindStream(pStmDest)); // Return pStmDest *ppStream = pStmDest; (*ppStream)->AddRef(); exit: // Cleanup SafeRelease(pStmSource); SafeRelease(pHdrTable); SafeRelease(pStmDest); // Done return hr; } // -------------------------------------------------------------------------------- // MimeOleGetWindowsCPEx // -------------------------------------------------------------------------------- CODEPAGEID MimeOleGetWindowsCPEx(LPINETCSETINFO pCharset) { // Invalid Arg if (NULL == pCharset) return CP_ACP; // Check for Auto-Detect if (CP_JAUTODETECT == pCharset->cpiWindows) return 932; else if (CP_ISO2022JPESC == pCharset->cpiWindows) return 932; else if (CP_ISO2022JPSIO == pCharset->cpiWindows) return 932; else if (CP_KAUTODETECT == pCharset->cpiWindows) return 949; else return pCharset->cpiWindows; } // -------------------------------------------------------------------------------- // MimeOleClearDirtyTree // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleClearDirtyTree(IMimeMessageTree *pITree) { // Locals HRESULT hr=S_OK; CMessageTree *pTree=NULL; // Invalid Arg if (NULL == pITree) return TrapError(E_INVALIDARG); // I need a private IID_CMessageTree to do this CHECKHR(hr = pITree->QueryInterface(IID_CMessageTree, (LPVOID *)&pTree)); // ClearDirty pTree->ClearDirty(); // Validate Assert(pTree->IsDirty() == S_FALSE); exit: // Cleanup SafeRelease(pTree); // Done return hr; } // -------------------------------------------------------------------------------- // PszDefaultSubType // -------------------------------------------------------------------------------- LPCSTR PszDefaultSubType(LPCSTR pszPriType) { if (lstrcmpi(pszPriType, STR_CNT_TEXT) == 0) return STR_SUB_PLAIN; else if (lstrcmpi(pszPriType, STR_CNT_MULTIPART) == 0) return STR_SUB_MIXED; else return STR_SUB_OCTETSTREAM; } // -------------------------------------------------------------------------------- // MimeOleContentTypeFromUrl // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleContentTypeFromUrl( /* in */ LPCSTR pszBase, /* in */ LPCSTR pszUrl, /* out */ LPSTR *ppszCntType) { // Locals HRESULT hr=S_OK; LPSTR pszFree=NULL; LPSTR pszCombined=NULL; LPWSTR pwszUrl=NULL; LPWSTR pwszCntType=NULL; // Invalid Arg if (NULL == pszUrl || NULL == ppszCntType) return TrapError(E_INVALIDARG); // Init *ppszCntType = NULL; // Combine the URL if (pszBase) { // Allocate Base + URL DWORD cchSize = (lstrlen(pszUrl) + lstrlen(pszBase) + 1); CHECKALLOC(pszFree = (LPSTR)g_pMalloc->Alloc(cchSize)); // Format It wnsprintfA(pszFree, cchSize, "%s%s", pszBase, pszUrl); // Set combined pszCombined = pszFree; // Convert to Unicode CHECKALLOC(pwszUrl = PszToUnicode(CP_ACP, pszCombined)); } // To Unicode else { // Set combined pszCombined = (LPSTR)pszUrl; // Convert to Unicode CHECKALLOC(pwszUrl = PszToUnicode(CP_ACP, pszUrl)); } // Get the Mime Content Type from the Url CHECKHR(hr = FindMimeFromData(NULL, pwszUrl, NULL, NULL, NULL, 0, &pwszCntType, 0)); // Convert to ANSI CHECKALLOC(*ppszCntType = PszToANSI(CP_ACP, pwszCntType)); exit: // Cleanup SafeMemFree(pszFree); SafeMemFree(pwszUrl); SafeMemFree(pwszCntType); // Done return hr; } // -------------------------------------------------------------------------------- // MimeOleObjectFromMoniker // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleObjectFromMoniker( /* in */ BINDF bindf, /* in */ IMoniker *pmkOriginal, /* in */ IBindCtx *pBindCtx, /* in */ REFIID riid, /* out */ LPVOID *ppvObject, /* out */ IMoniker **ppmkNew) { Assert(g_pUrlCache); return TrapError(g_pUrlCache->ActiveObjectFromMoniker(bindf, pmkOriginal, pBindCtx, riid, ppvObject, ppmkNew)); } // -------------------------------------------------------------------------------- // MimeOleObjectFromUrl // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleObjectFromUrl( /* in */ LPCSTR pszUrl, /* in */ BOOL fCreate, /* in */ REFIID riid, /* out */ LPVOID *ppvObject, /* out */ IUnknown **ppUnkKeepAlive) { Assert(g_pUrlCache); return TrapError(g_pUrlCache->ActiveObjectFromUrl(pszUrl, fCreate, riid, ppvObject, ppUnkKeepAlive)); } // -------------------------------------------------------------------------------- // MimeOleCombineMhtmlUrl // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleCombineMhtmlUrl( /* in */ LPSTR pszRootUrl, /* in */ LPSTR pszBodyUrl, /* out */ LPSTR *ppszUrl) { // Locals HRESULT hr=S_OK; ULONG cchPrefix=lstrlen(c_szMHTMLColon); // Invalid Arg if (NULL == pszRootUrl || NULL == pszBodyUrl || NULL == ppszUrl) return TrapError(E_INVALIDARG); // Init *ppszUrl = NULL; // Allocate memory: pszRootUrl + ! + pszBodyUrl DWORD cchSize = (cchPrefix + lstrlen(pszRootUrl) + lstrlen(pszBodyUrl) + 2); CHECKALLOC(*ppszUrl = (LPSTR)g_pMalloc->Alloc(cchSize)); // Root must start with mhtml://pszRootUrl!pszBodyUrl if (StrCmpNI(pszRootUrl, c_szMHTMLColon, cchPrefix) != 0) wnsprintfA(*ppszUrl, cchSize, "%s%s!%s", c_szMHTMLColon, pszRootUrl, pszBodyUrl); else wnsprintfA(*ppszUrl, cchSize, "%s!%s", pszRootUrl, pszBodyUrl); exit: // Done return hr; } // -------------------------------------------------------------------------------- // MimeOleSplitMhtmlUrl - Returns E_INVLAIDARG if pszUrl does not start with mhtml: // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleParseMhtmlUrl( /* in */ LPSTR pszUrl, /* out */ LPSTR *ppszRootUrl, /* out */ LPSTR *ppszBodyUrl) { // Locals HRESULT hr=S_OK; CStringParser cString; CHAR chToken; ULONG cchUrl; ULONG cchPrefix=lstrlen(c_szMHTMLColon); // Invalid Arg if (NULL == pszUrl) return TrapError(E_INVALIDARG); // Init if (ppszRootUrl) *ppszRootUrl = NULL; if (ppszBodyUrl) *ppszBodyUrl = NULL; // No an mhtml Url ? if (StrCmpNI(pszUrl, c_szMHTMLColon, cchPrefix) != 0) { hr = E_FAIL; goto exit; } // Get the length cchUrl = lstrlen(pszUrl); // Init the Parser cString.Init(pszUrl + cchPrefix, cchUrl - cchPrefix, PSF_NOFRONTWS | PSF_NOTRAILWS); // Skip Over any '/' cString.ChSkip("/"); // Parse chToken = cString.ChParse("!"); if (0 == cString.CchValue()) { hr = TrapError(E_FAIL); goto exit; } // Client Wants ppszRootUrl if (ppszRootUrl) { // Allocate length for root part CHECKALLOC(*ppszRootUrl = (LPSTR)g_pMalloc->Alloc(cString.CchValue() + 1)); // Copy It CopyMemory((LPBYTE)*ppszRootUrl, (LPBYTE)cString.PszValue(), cString.CchValue() + 1); } // Client Wants ppszBodyUrl if (ppszBodyUrl) { // Parse to the end of the string chToken = cString.ChParse(NULL); Assert('\0' == chToken); // Is there data if (cString.CchValue() > 0) { // Allocate length for root part CHECKALLOC(*ppszBodyUrl = (LPSTR)g_pMalloc->Alloc(cString.CchValue() + 1)); // Copy It CopyMemory((LPBYTE)*ppszBodyUrl, (LPBYTE)cString.PszValue(), cString.CchValue() + 1); } } exit: // Failure if (FAILED(hr)) { if (ppszRootUrl) SafeMemFree(*ppszRootUrl); if (ppszBodyUrl) SafeMemFree(*ppszBodyUrl); } // Done return hr; } // -------------------------------------------------------------------------------- // MimeOleCombineURL // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleCombineURL( /* in */ LPCSTR pszBase, /* in */ ULONG cchBase, /* in */ LPCSTR pszURL, /* in */ ULONG cchURL, /* in */ BOOL fUnEscape, /* out */ LPSTR *ppszAbsolute) { // Locals HRESULT hr=S_OK; LPWSTR pwszBase=NULL; LPWSTR pwszUrl=NULL; LPWSTR pwszCombined=NULL; ULONG cchCombined; ULONG cchActual; WCHAR wchCombined[255]; LPSTR pszT; CStringParser cString; // Invalid Arg if (NULL == pszBase || '\0' != pszBase[cchBase] || NULL == pszURL || '\0' != pszURL[cchURL] || NULL == ppszAbsolute) return TrapError(E_INVALIDARG); // INit *ppszAbsolute = NULL; // Raid-2621: Mail : Can't display images when message is only in HTML and the Content Base is in the headers pszT = PszSkipWhiteA((LPSTR)pszBase); if (pszT && '\"' == *pszT) { // Init the String cString.Init(pszBase, cchBase, PSF_NOTRAILWS | PSF_NOFRONTWS | PSF_ESCAPED | PSF_DBCS); // Remove Quotes if ('\"' == cString.ChParse("\"") && '\"' == cString.ChParse("\"")) { // Reset pszBase pszBase = cString.PszValue(); cchBase = cString.CchValue(); } } // Convert to Wide CHECKALLOC(pwszBase = PszToUnicode(CP_ACP, pszBase)); CHECKALLOC(pwszUrl = PszToUnicode(CP_ACP, pszURL)); // Combine if (SUCCEEDED(CoInternetCombineUrl(pwszBase, pwszUrl, 0, wchCombined, ARRAYSIZE(wchCombined) - 1, &cchCombined, 0))) { // Convert to ANSI CHECKALLOC(*ppszAbsolute = PszToANSI(CP_ACP, wchCombined)); } // Otherwise, allocate else { // Allocate CHECKALLOC(pwszCombined = PszAllocW(cchCombined)); // Combine CHECKHR(hr = CoInternetCombineUrl(pwszBase, pwszUrl, 0, pwszCombined, cchCombined, &cchActual, 0)); // Valid? Assert(cchCombined == cchActual); // Convert to ANSI CHECKALLOC(*ppszAbsolute = PszToANSI(CP_ACP, pwszCombined)); } // Unescape if (fUnEscape) { // Do it CHECKHR(hr = UrlUnescapeA(*ppszAbsolute, NULL, NULL, URL_UNESCAPE_INPLACE)); } exit: // Cleanup SafeMemFree(pwszBase); SafeMemFree(pwszUrl); SafeMemFree(pwszCombined); // Done return hr; } // -------------------------------------------------------------------------------- // MimeOleGetSubjectFileName // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleGetSubjectFileName(IMimePropertySet *pPropertySet, ULONG *pulPart, ULONG *pulTotal, LPSTR pszFileName, ULONG cchMax) { return E_FAIL; #if 0 // Locals HRESULT hr=S_OK; PROPVARIANT rSubject; PARSESTRINGINFO rParse; PARSESTRINGINFO rTemp; CHAR szScratch[255], szFileName[MAX_PATH]; ULONG i, iString; BOOL fValid; // Invalid Arg if (NULL == pPropertySet || NULL == pszFileName || NULL == pulPart || NULL == pulTotal) return TrapError(E_INVALIDARG); // Zero the Structure ZeroMemory(&rParse, sizeof(PARSESTRINGINFO)); // Init *pulPart = 0; *pulTotal = 0; *pszFileName = '\0'; *szFileName = '\0'; // Init rSubject.vt = VT_LPSTR; rSubject.pszVal = NULL; // Get the subject CHECKHR(hr = pPropertySet->GetProp(PIDTOSTR(PID_HDR_SUBJECT), 0, &rSubject)); // Set the Members rParse.cpiCodePage = CP_ACP; rParse.pszString = rSubject.pszVal; rParse.cchString = lstrlen(rSubject.pszVal); rParse.pszScratch = szScratch; rParse.pszValue = szScratch; rParse.cchValMax = sizeof(szScratch); rParse.dwFlags = PARSTR_SKIP_FORWARD_WS | PARSTR_STRIP_TRAILING_WS | PARSTR_GROW_VALUE_ALLOWED; // Initialize My String Parser MimeOleSetParseTokens(&rParse, " (["); // Loop for a while while(1) { // Parse up to colon CHECKHR(hr = MimeOleParseString(&rParse)); // Done if (rParse.fDone) break; // Space, just save the last value if (' ' == rParse.chToken) { // Less than MAX_PATH if (rParse.cchValue < MAX_PATH) StrCpyN(szFileName, rParse.pszValue, ARRAYSIZE(szFileName)); } // Loop Next few characters (001\010) else { // Less than MAX_PATH if (rParse.cchValue && rParse.cchValue < MAX_PATH) StrCpyN(szFileName, rParse.pszValue, ARRAYSIZE(szFileName)); // Save the Current State iString = rParse.iString; // Find the Ending Token if ('(' == rParse.chToken) MimeOleSetParseTokens(&rParse, ")"); else MimeOleSetParseTokens(&rParse, "]"); // Parse up to colon CHECKHR(hr = MimeOleParseString(&rParse)); // Done if (rParse.fDone) break; // (000/000) All Numbers in rParse.pszValue are numbers for (fValid=TRUE, i=0; iHrInitialize(pszBase, pszURL)); // Return It *ppDocument = (IMimeWebDocument *)pDocument; (*ppDocument)->AddRef(); exit: // Cleanup SafeRelease(pDocument); // Done return hr; } // -------------------------------------------------------------------------------- // MimeOleComputeContentBase // -------------------------------------------------------------------------------- HRESULT MimeOleComputeContentBase(IMimeMessage *pMessage, HBODY hRelated, LPSTR *ppszBase, BOOL *pfMultipartBase) { // Locals HRESULT hr=S_OK; HBODY hBase=NULL; // Init if (pfMultipartBase) *pfMultipartBase = FALSE; // If no hRelated was passed in, lets try to find one if (NULL == hRelated) { // Find the related section if (FAILED(MimeOleGetRelatedSection(pMessage, FALSE, &hRelated, NULL))) { // Get the root body pMessage->GetBody(IBL_ROOT, NULL, &hRelated); } } // Get the text/html body if (FAILED(pMessage->GetTextBody(TXT_HTML, IET_BINARY, NULL, &hBase))) hBase = hRelated; // No Base if (NULL == hBase) { hr = E_FAIL; goto exit; } // Call utility function *ppszBase = MimeOleContentBaseFromBody(pMessage, hBase); // If that failed and we used the text body if (NULL == *ppszBase && hRelated && hBase != hRelated) *ppszBase = MimeOleContentBaseFromBody(pMessage, hRelated); // Did this come from the multipart related if (NULL != *ppszBase && hBase == hRelated && pfMultipartBase) *pfMultipartBase = TRUE; exit: // Done return hr; } // -------------------------------------------------------------------------------- // MimeOleContentBaseFromBody // -------------------------------------------------------------------------------- LPSTR MimeOleContentBaseFromBody(IMimeMessageTree *pTree, HBODY hBody) { // Locals PROPVARIANT rVariant; // Setup Variant rVariant.vt = VT_LPSTR; rVariant.pszVal = NULL; // Get Content-Base first, and then try Content-Location if (FAILED(pTree->GetBodyProp(hBody, PIDTOSTR(PID_HDR_CNTBASE), NOFLAGS, &rVariant))) { // Try Content-Location if (FAILED(pTree->GetBodyProp(hBody, PIDTOSTR(PID_HDR_CNTLOC), NOFLAGS, &rVariant))) rVariant.pszVal = NULL; } // Return return rVariant.pszVal; } // -------------------------------------------------------------------------------- // MimeOleGetRelatedSection // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleGetRelatedSection( IMimeMessageTree *pTree, boolean fCreate, LPHBODY phRelated, boolean *pfMultiple) { // Locals HRESULT hr=S_OK; HBODY hRoot; FINDBODY rFind; PROPVARIANT rVariant; // Invalid Args if (NULL == pTree || NULL == phRelated) return TrapError(E_INVALIDARG); // Init ZeroMemory(&rFind, sizeof(FINDBODY)); // Find first multipart/related section rFind.pszPriType = (LPSTR)STR_CNT_MULTIPART; rFind.pszSubType = (LPSTR)STR_SUB_RELATED; // Init if (pfMultiple) *pfMultiple = FALSE; // Find First if (SUCCEEDED(pTree->FindFirst(&rFind, phRelated))) { // Is there another multipart/related section if (pfMultiple && SUCCEEDED(pTree->FindNext(&rFind, &hRoot))) *pfMultiple = TRUE; // Done goto exit; } // If no Create, fail if (FALSE == fCreate) { hr = TrapError(MIME_E_NOT_FOUND); goto exit; } // Get the Root Body CHECKHR(hr = pTree->GetBody(IBL_ROOT, NULL, &hRoot)); // Setup Variant rVariant.vt = VT_LPSTR; rVariant.pszVal = (LPSTR)STR_MIME_MPART_RELATED; // If Root is empty if (pTree->IsBodyType(hRoot, IBT_EMPTY) == S_OK) { // Set the Content Type CHECKHR(hr = pTree->SetBodyProp(hRoot, PIDTOSTR(PID_HDR_CNTTYPE), 0, &rVariant)); // Set phRelated *phRelated = hRoot; } // If root is non-multipart, convert it to multipart/related else if (pTree->IsContentType(hRoot, STR_CNT_MULTIPART, NULL) == S_FALSE) { // Conver this body to a multipart/related CHECKHR(hr = pTree->ToMultipart(hRoot, STR_SUB_RELATED, phRelated)); } // Otherwise, if root is multipart/mixed else if (pTree->IsContentType(hRoot, NULL, STR_SUB_MIXED) == S_OK) { // Insert First Child of multipart/mixed as multipart/related CHECKHR(hr = pTree->InsertBody(IBL_FIRST, hRoot, phRelated)); // Set the Content Type CHECKHR(hr = pTree->SetBodyProp(*phRelated, PIDTOSTR(PID_HDR_CNTTYPE), 0, &rVariant)); } // Otherwise, if root is multipart/alternative else if (pTree->IsContentType(HBODY_ROOT, NULL, STR_SUB_ALTERNATIVE) == S_OK) { // Convert this body to a multipart/related (alternative becomes first child) CHECKHR(hr = pTree->ToMultipart(HBODY_ROOT, STR_SUB_RELATED, phRelated)); // Should I set multipart/related; start=multipart/alternative at this point ? } // Otherwise, for unknown multipart content types else { // Convert this body to a multipart/related CHECKHR(hr = pTree->ToMultipart(HBODY_ROOT, STR_SUB_RELATED, phRelated)); } exit: // Done return hr; } // -------------------------------------------------------------------------------- // MimeOleGetMixedSection // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleGetMixedSection( IMimeMessageTree *pTree, boolean fCreate, LPHBODY phMixed, boolean *pfMultiple) { // Locals HRESULT hr=S_OK; HBODY hTemp; HBODY hRoot; FINDBODY rFind; PROPVARIANT rVariant; // Invalid Args if (NULL == pTree || NULL == phMixed) return TrapError(E_INVALIDARG); // Init ZeroMemory(&rFind, sizeof(FINDBODY)); // Find first multipart/mixed section rFind.pszPriType = (LPSTR)STR_CNT_MULTIPART; rFind.pszSubType = (LPSTR)STR_SUB_MIXED; // Find First if (SUCCEEDED(pTree->FindFirst(&rFind, phMixed))) { // Is there another multipart/mixed section if (pfMultiple && SUCCEEDED(pTree->FindNext(&rFind, &hTemp))) *pfMultiple = TRUE; // Done goto exit; } // Init if (pfMultiple) *pfMultiple = FALSE; // If no Create, fail if (FALSE == fCreate) { hr = TrapError(MIME_E_NOT_FOUND); goto exit; } // Get the Root Body CHECKHR(hr = pTree->GetBody(IBL_ROOT, NULL, &hRoot)); // If Root is empty if (pTree->IsBodyType(hRoot, IBT_EMPTY) == S_OK) { // Setup Variant rVariant.vt = VT_LPSTR; rVariant.pszVal = (LPSTR)STR_MIME_MPART_MIXED; // Set the Content Type CHECKHR(hr = pTree->SetBodyProp(hRoot, PIDTOSTR(PID_HDR_CNTTYPE), 0, &rVariant)); // Set phRelated *phMixed = hRoot; } // Otherwise, convert it to a multipart else { // Conver this body to a multipart/mixed CHECKHR(hr = pTree->ToMultipart(HBODY_ROOT, STR_SUB_MIXED, phMixed)); } exit: // Done return hr; } // -------------------------------------------------------------------------------- // MimeOleGetAlternativeSection // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleGetAlternativeSection( IMimeMessageTree *pTree, LPHBODY phAlternative, boolean *pfMultiple) { // Locals HRESULT hr=S_OK; HBODY hTemp; FINDBODY rFind; // Invalid Args if (NULL == pTree || NULL == phAlternative) return TrapError(E_INVALIDARG); // Init ZeroMemory(&rFind, sizeof(FINDBODY)); // Find first multipart/mixed section rFind.pszPriType = (LPSTR)STR_CNT_MULTIPART; rFind.pszSubType = (LPSTR)STR_SUB_ALTERNATIVE; // Find First if (SUCCEEDED(pTree->FindFirst(&rFind, phAlternative))) { // Is there another multipart/mixed section if (pfMultiple && SUCCEEDED(pTree->FindNext(&rFind, &hTemp))) *pfMultiple = TRUE; // Done goto exit; } // Init if (pfMultiple) *pfMultiple = FALSE; // If no Create, fail hr = TrapError(MIME_E_NOT_FOUND); exit: // Done return hr; } // ------------------------------------------------------------------------------------------ // MimeOleGenerateCID // ------------------------------------------------------------------------------------------ MIMEOLEAPI MimeOleGenerateCID(LPSTR pszCID, ULONG cchMax, boolean fAbsolute) { // Locals HRESULT hr=S_OK; ULONG cch; FILETIME ft; SYSTEMTIME st; WORD wCounter; // Invalid Arg if (NULL == pszCID) return TrapError(E_INVALIDARG); // Get Current Time GetSystemTime(&st); // Convert to FileTime SystemTimeToFileTime(&st, &ft); // Build MessageID if (FALSE == fAbsolute) cch = wnsprintfA(pszCID, cchMax, "%04x%08.8lx$%08.8lx$%s@%s", DwCounterNext(), ft.dwHighDateTime, ft.dwLowDateTime, (LPTSTR)SzGetLocalPackedIP(), PszGetDomainName()); else cch = wnsprintfA(pszCID, cchMax, "CID:%04x%08.8lx$%08.8lx$%s@%s", DwCounterNext(), ft.dwHighDateTime, ft.dwLowDateTime, (LPTSTR)SzGetLocalPackedIP(), PszGetDomainName()); // Buffer Overwrite Assert(cch + 1 <= CCHMAX_CID); // Done return hr; } // ------------------------------------------------------------------------------------------ // MimeOleGenerateMID // ------------------------------------------------------------------------------------------ MIMEOLEAPI MimeOleGenerateMID(LPSTR pszMID, ULONG cchMax, boolean fAbsolute) { // Locals HRESULT hr=S_OK; ULONG cch; FILETIME ft; SYSTEMTIME st; WORD wCounter; // Invalid Arg if (NULL == pszMID || cchMax < CCHMAX_MID) return TrapError(E_INVALIDARG); // Get Current Time GetSystemTime(&st); // Convert to FileTime SystemTimeToFileTime(&st, &ft); // Build MessageID if (FALSE == fAbsolute) cch = wnsprintfA(pszMID, cchMax, "<%04x%08.8lx$%08.8lx$%s@%s>", DwCounterNext(), ft.dwHighDateTime, ft.dwLowDateTime, (LPTSTR)SzGetLocalPackedIP(), PszGetDomainName()); else cch = wnsprintfA(pszMID, cchMax, "MID:%04x%08.8lx$%08.8lx$%s@%s", DwCounterNext(), ft.dwHighDateTime, ft.dwLowDateTime, (LPTSTR)SzGetLocalPackedIP(), PszGetDomainName()); // Buffer Overwrite Assert(cch + 1 <= CCHMAX_MID); // Done return hr; } // ------------------------------------------------------------------------------------------ // MimeOleCreateByteStream // ------------------------------------------------------------------------------------------ MIMEOLEAPI MimeOleCreateByteStream( IStream **ppStream) { // Locals HRESULT hr=S_OK; // Invalid Arg if (NULL == ppStream) return TrapError(E_INVALIDARG); // Alocate It CHECKALLOC((*ppStream) = new CByteStream); exit: // Done return hr; } // ------------------------------------------------------------------------------------------ // MimeOleGetPropertySchema // ------------------------------------------------------------------------------------------ MIMEOLEAPI MimeOleGetPropertySchema( IMimePropertySchema **ppSchema) { // Locals HRESULT hr=S_OK; // check params if (NULL == ppSchema) return TrapError(E_INVALIDARG); // Out of memory if (NULL == g_pSymCache) return TrapError(E_OUTOFMEMORY); // Create me *ppSchema = (IMimePropertySchema *)g_pSymCache; // Add Ref (*ppSchema)->AddRef(); // Done return S_OK; } // ------------------------------------------------------------------------------------------ // MimeOleCreateHeaderTable // ------------------------------------------------------------------------------------------ MIMEOLEAPI MimeOleCreateHeaderTable(IMimeHeaderTable **ppTable) { // Locals HRESULT hr=S_OK; LPCONTAINER pContainer=NULL; // check params if (NULL == ppTable) return TrapError(E_INVALIDARG); // Create a new Container Object CHECKALLOC(pContainer = new CMimePropertyContainer); // Init CHECKHR(hr = pContainer->InitNew()); // Bind to Header table CHECKHR(hr = pContainer->QueryInterface(IID_IMimeHeaderTable, (LPVOID *)ppTable)); exit: // Failure SafeRelease(pContainer); // Done return hr; } // ------------------------------------------------------------------------------------------ // MimeOleCreateVirtualStream // ------------------------------------------------------------------------------------------ MIMEOLEAPI MimeOleCreateVirtualStream(IStream **ppStream) { // Locals HRESULT hr=S_OK; // check params if (NULL == ppStream) return TrapError(E_INVALIDARG); // Allocate Virtual Stream *ppStream = new CVirtualStream; if (NULL == *ppStream) { hr = TrapError(E_OUTOFMEMORY); goto exit; } exit: // Done return hr; } // ------------------------------------------------------------------------------------------ // MimeOleOpenFileStream // ------------------------------------------------------------------------------------------ MIMEOLEAPI MimeOleOpenFileStream(LPCSTR pszFilePath, DWORD dwCreationDistribution, DWORD dwAccess, IStream **ppstmFile) { // Invalid Arg if (NULL == pszFilePath || NULL == ppstmFile) return TrapError(E_INVALIDARG); // Call Internal Tool return OpenFileStream((LPSTR)pszFilePath, dwCreationDistribution, dwAccess, ppstmFile); } // ------------------------------------------------------------------------------------------ // MimeOleIsEnrichedStream, text must start with // ------------------------------------------------------------------------------------------ MIMEOLEAPI MimeOleIsEnrichedStream(IStream *pStream) { // Locals HRESULT hr=S_OK; LPSTR pszT; BYTE rgbBuffer[30 + 1]; ULONG cbRead; // Invalid Arg if (NULL == pStream) return TrapError(E_INVALIDARG); // Rewind the stream CHECKHR(hr = HrRewindStream(pStream)); // Read the first four bytes CHECKHR(hr = pStream->Read(rgbBuffer, sizeof(rgbBuffer) - 1, &cbRead)); // Less than four bytes read ? if (cbRead < (ULONG)lstrlen(c_szXRich)) { hr = S_FALSE; goto exit; } // Stick in a null rgbBuffer[cbRead] = '\0'; // Skip White Space pszT = (LPSTR)rgbBuffer; // Skip White pszT = PszSkipWhiteA(pszT); if ('\0' == *pszT) { hr = S_FALSE; goto exit; } // Compare if (StrCmpNI(pszT, c_szXRich, lstrlen(c_szXRich)) != 0) { hr = S_FALSE; goto exit; } exit: // Done return hr; } // ------------------------------------------------------------------------------------------ // MimeOleIsTnefStream // ------------------------------------------------------------------------------------------ MIMEOLEAPI MimeOleIsTnefStream(IStream *pStream) { // Locals HRESULT hr=S_OK; BYTE rgbSignature[4]; ULONG cbRead; // Invalid Arg if (NULL == pStream) return TrapError(E_INVALIDARG); // Read the first four bytes CHECKHR(hr = pStream->Read(rgbSignature, sizeof(rgbSignature), &cbRead)); // Less than four bytes read ? if (cbRead < 4) { hr = S_FALSE; goto exit; } // Compare bytes if (rgbSignature[0] != 0x78 && rgbSignature[1] != 0x9f && rgbSignature[2] != 0x3e && rgbSignature[3] != 0x22) { hr = S_FALSE; goto exit; } // Its TNEF hr = S_OK; exit: // Done return hr; } // -------------------------------------------------------------------------------- // MimeOleGenerateFileName // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleGenerateFileName(LPCSTR pszContentType, LPCSTR pszSuggest, LPCSTR pszDefaultExt, LPSTR *ppszFileName) { // Locals HRESULT hr=S_OK; LPSTR pszExt=NULL, pszName=NULL; CHAR szName[10]; LPCSTR pszExtension=NULL, pszPrefix=NULL; // Invalid Arg if (NULL == ppszFileName) return TrapError(E_INVALIDARG); // Init *ppszFileName = NULL; // Find a filename extension if (pszContentType) { // Get the content type... if (SUCCEEDED(MimeOleGetContentTypeExt(pszContentType, &pszExt))) pszExtension = (LPCSTR)pszExt; } // Extension is still null if (NULL == pszExtension) { // Use default extension... if (pszDefaultExt) pszExtension = pszDefaultExt; // Otherwise, internal default else pszExtension = c_szDotDat; } // We Should have an extension Assert(pszExtension); // Suggested file name ? if (pszSuggest) { // Dup It pszName = PszDupA(pszSuggest); if (NULL == pszName) { hr = TrapError(E_OUTOFMEMORY); goto exit; } // Dupit and remove illegal filename characters... CleanupFileNameInPlaceA(CP_ACP, pszName); // Set Prefix pszPrefix = (LPCSTR)pszName; } // Otherwise, build a filename... else { // Locals CHAR szNumber[30]; // Get a number... wnsprintfA(szNumber, ARRAYSIZE(szNumber), "%05d", DwCounterNext()); // Allocate pszName wnsprintfA(szName, ARRAYSIZE(szName), "ATT%s", szNumber); // Set Prefix pszPrefix = (LPCSTR)szName; } // Build Final FileNmae= pszPrefix + pszExtension + dot + null DWORD cchSize = (lstrlen(pszPrefix) + lstrlen(pszExtension) + 2); *ppszFileName = PszAllocA(cchSize); if (NULL == *ppszFileName) { hr = TrapError(E_OUTOFMEMORY); goto exit; } // Build filename wnsprintfA(*ppszFileName, cchSize, "%s%s", pszPrefix, pszExtension); exit: // Failure if (FAILED(hr) && E_OUTOFMEMORY != hr) { // Assume Success hr = S_OK; // Use default Attachment name *ppszFileName = PszDupA(c_szDefaultAttach); // Memory Failure if (NULL == *ppszFileName) hr = TrapError(E_OUTOFMEMORY); } // Cleanup SafeMemFree(pszExt); SafeMemFree(pszName); // Done return hr; } // -------------------------------------------------------------------------------- // MimeOleGenerateFileNameW // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleGenerateFileNameW(LPCSTR pszContentType, LPCWSTR pszSuggest, LPCWSTR pszDefaultExt, LPWSTR *ppszFileName) { // Locals HRESULT hr=S_OK; LPSTR pszExtA=NULL; LPWSTR pszExtW=NULL; LPWSTR pszName=NULL; WCHAR szName[10]; LPWSTR pszExtension=NULL; LPWSTR pszPrefix=NULL; int cch = 0; // Invalid Arg if (NULL == ppszFileName) return TrapError(E_INVALIDARG); // Init *ppszFileName = NULL; // Find a filename extension if (pszContentType) { // Get the content type... if (SUCCEEDED(MimeOleGetContentTypeExt(pszContentType, &pszExtA))) { // I'm going to convert to unicode because I assume extensions are usascii IF_NULLEXIT(pszExtW = PszToUnicode(CP_ACP, pszExtA)); // Save as the extension pszExtension = pszExtW; } } // Extension is still null if (NULL == pszExtension) { // Use default extension... if (pszDefaultExt) pszExtension = (LPWSTR)pszDefaultExt; // Otherwise, internal default else pszExtension = (LPWSTR)c_wszDotDat; } // We Should have an extension Assert(pszExtension); // Suggested file name ? if (pszSuggest) { // Dup It IF_NULLEXIT(pszName = PszDupW(pszSuggest)); // Dupit and remove illegal filename characters... CleanupFileNameInPlaceW(pszName); // Set Prefix pszPrefix = pszName; } // Otherwise, build a filename... else { // Locals WCHAR szNumber[30]; // Get a number... wnsprintfW(szNumber, ARRAYSIZE(szNumber), L"%05d", DwCounterNext()); // Allocate pszName wnsprintfW(szName, ARRAYSIZE(szName), L"ATT%s", szNumber); // Set Prefix pszPrefix = szName; } // Build Final FileNmae= pszPrefix + pszExtension + dot + null cch = lstrlenW(pszPrefix) + lstrlenW(pszExtension) + 2; IF_NULLEXIT(*ppszFileName = PszAllocW(cch)); // Build filename wnsprintfW(*ppszFileName, cch, L"%s%s", pszPrefix, pszExtension); exit: // Failure if (FAILED(hr) && E_OUTOFMEMORY != hr) { // Assume Success hr = S_OK; // Use default Attachment name *ppszFileName = PszDupW(c_wszDefaultAttach); // Memory Failure if (NULL == *ppszFileName) hr = TrapError(E_OUTOFMEMORY); } // Cleanup SafeMemFree(pszExtA); SafeMemFree(pszExtW); SafeMemFree(pszName); // Done return hr; } // -------------------------------------------------------------------------------- // CreateMimeSecurity // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleCreateSecurity(IMimeSecurity **ppSecurity) { // check params if (NULL == ppSecurity) return TrapError(E_INVALIDARG); // Create the object *ppSecurity = (IMimeSecurity *) new CSMime; if (NULL == *ppSecurity) return TrapError(E_OUTOFMEMORY); // Done return S_OK; } // ------------------------------------------------------------------------------------------ // MimeOleCreateMessageParts // ------------------------------------------------------------------------------------------ MIMEOLEAPI MimeOleCreateMessageParts(IMimeMessageParts **ppParts) { // Locals HRESULT hr=S_OK; CMimeMessageParts *pParts=NULL; // check params if (NULL == ppParts) return TrapError(E_INVALIDARG); // Init *ppParts = NULL; // Allocate Message Parts pParts = new CMimeMessageParts; if (NULL == pParts) { hr = TrapError(E_OUTOFMEMORY); goto exit; } // Success *ppParts = pParts; (*ppParts)->AddRef(); exit: // Done SafeRelease(pParts); // Done return hr; } // ------------------------------------------------------------------------------------------ // MimeOleGetAllocator // ------------------------------------------------------------------------------------------ MIMEOLEAPI MimeOleGetAllocator(IMimeAllocator **ppMalloc) { // Locals HRESULT hr=S_OK; // check params if (NULL == ppMalloc) return TrapError(E_INVALIDARG); // Allocate MimeOleMalloc *ppMalloc = new CMimeAllocator; if (NULL == *ppMalloc) { hr = TrapError(E_OUTOFMEMORY); goto exit; } exit: // Done return hr; } // ------------------------------------------------------------------------------------------ // MimeOleCreateMessage // ------------------------------------------------------------------------------------------ MIMEOLEAPI MimeOleCreateHashTable(DWORD dwSize, BOOL fDupeKeys, IHashTable **ppHashTable) { // Locals HRESULT hr=S_OK; IHashTable *pHash; // check params if (NULL == ppHashTable) return TrapError(E_INVALIDARG); // Init *ppHashTable = NULL; // Allocate MimeMessage CHECKALLOC(pHash = new CHash(NULL)); // Init New CHECKHR(hr = pHash->Init(dwSize, fDupeKeys)); // Success *ppHashTable = pHash; (*ppHashTable)->AddRef(); exit: // Done SafeRelease(pHash); // Done return hr; } // ------------------------------------------------------------------------------------------ // MimeOleCreateMessage // ------------------------------------------------------------------------------------------ MIMEOLEAPI MimeOleCreateMessage(IUnknown *pUnkOuter, IMimeMessage **ppMessage) { // Locals HRESULT hr=S_OK; LPMESSAGETREE pTree=NULL; // check params if (NULL == ppMessage) return TrapError(E_INVALIDARG); // Init *ppMessage = NULL; // Allocate MimeMessage CHECKALLOC(pTree = new CMessageTree(pUnkOuter)); // Init New CHECKHR(hr = pTree->InitNew()); // Success *ppMessage = pTree; (*ppMessage)->AddRef(); exit: // Done SafeRelease(pTree); // Done return hr; } // ------------------------------------------------------------------------------------------ // MimeOleCreateMessageTree // ------------------------------------------------------------------------------------------ MIMEOLEAPI MimeOleCreateMessageTree(IUnknown *pUnkOuter, IMimeMessageTree **ppMessageTree) { // Locals HRESULT hr=S_OK; LPMESSAGETREE pTree=NULL; // check params if (NULL == ppMessageTree) return TrapError(E_INVALIDARG); // INit *ppMessageTree = NULL; // Allocate MimeMessageTree CHECKALLOC(pTree = new CMessageTree(pUnkOuter)); // Init New CHECKHR(hr = pTree->InitNew()); // Success *ppMessageTree = pTree; (*ppMessageTree)->AddRef(); exit: // Done SafeRelease(pTree); // Done return hr; } // ------------------------------------------------------------------------------------------ // MimeOleCreatePropertySet // ------------------------------------------------------------------------------------------ MIMEOLEAPI MimeOleCreatePropertySet(IUnknown *pUnkOuter, IMimePropertySet **ppPropertySet) { // Locals HRESULT hr=S_OK; LPMESSAGEBODY pBody=NULL; // check params if (NULL == ppPropertySet) return TrapError(E_INVALIDARG); // Init *ppPropertySet = NULL; // Allocate MimePropertySet CHECKALLOC(pBody = new CMessageBody(NULL, pUnkOuter)); // Init New CHECKHR(hr = pBody->InitNew()); // Success *ppPropertySet = (IMimePropertySet *)pBody; (*ppPropertySet)->AddRef(); exit: // Done SafeRelease(pBody); // Done return hr; } // -------------------------------------------------------------------------------- // MimeOleMergePartialHeaders // ------------------------------- // Rules // ----- // (1) All of the header fields from the initial enclosing entity // (part one), except those that start with "Content-" and the // specific header fields "Message-ID", "Encrypted", and "MIME- // Version", must be copied, in order, to the new message. // // (2) Only those header fields in the enclosed message which start // with "Content-" and "Message-ID", "Encrypted", and "MIME-Version" // must be appended, in order, to the header fields of the new // message. Any header fields in the enclosed message which do not // start with "Content-" (except for "Message-ID", "Encrypted", and // "MIME-Version") will be ignored. // // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleMergePartialHeaders(IStream *pstmIn, IStream *pstmOut) { // Locals HRESULT hr = S_OK; LPCONTAINER pc1=NULL; LPCONTAINER pc2=NULL; ULONG i; ULONG cboffStart; CInternetStream cInternet; LONG iColon; PROPSTRINGA rHeader; PROPVARIANT rOption; // check params if (NULL == pstmIn || NULL == pstmOut) return TrapError(E_INVALIDARG); // Create text stream object CHECKHR(hr = cInternet.HrInitNew(pstmIn)); // Create Property Sets CHECKALLOC(pc1 = new CMimePropertyContainer); CHECKALLOC(pc2 = new CMimePropertyContainer); // Init CHECKHR(hr = pc1->InitNew()); CHECKHR(hr = pc2->InitNew()); // Load the first header CHECKHR(hr = pc1->Load(&cInternet)); // RAID-18376: POPDOG adds extra lines after the header, so I must read the blank lines // until I hit the next header, then backup. while(1) { // Get current position cboffStart = cInternet.DwGetOffset(); // Read a line CHECKHR(hr = cInternet.HrReadHeaderLine(&rHeader, &iColon)); // If line is not empty, assume its the start of the next header... if ('\0' != *rHeader.pszVal) { // Line better have a length Assert(rHeader.cchVal); // Reset position back to cboffStart cInternet.Seek(cboffStart); // Done break; } } // Load the second header CHECKHR(hr = pc2->Load(&cInternet)); // Delete Props From Header 1 for (i=0; iDeleteProp(g_rgszPartialPids[i]); // Delete Except from header 2 pc2->DeleteExcept(ARRAYSIZE(g_rgszPartialPids), g_rgszPartialPids); // Save as Mime rOption.vt = VT_UI4; rOption.ulVal = SAVE_RFC1521; // Store Some Options pc1->SetOption(OID_SAVE_FORMAT, &rOption); pc2->SetOption(OID_SAVE_FORMAT, &rOption); // Don't default to text/plain if Content-Type is not yet set... rOption.vt = VT_BOOL; rOption.boolVal = TRUE; pc1->SetOption(OID_NO_DEFAULT_CNTTYPE, &rOption); pc2->SetOption(OID_NO_DEFAULT_CNTTYPE, &rOption); // Save Header 1 CHECKHR(hr = pc1->Save(pstmOut, TRUE)); CHECKHR(hr = pc2->Save(pstmOut, TRUE)); exit: // Cleanup SafeRelease(pc1); SafeRelease(pc2); // Done return hr; } // -------------------------------------------------------------------------------- // MimeOleParseRfc822Address // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleParseRfc822Address( DWORD dwAdrType, ENCODINGTYPE ietEncoding, LPCSTR pszRfc822Adr, LPADDRESSLIST pList) { // Locals CMimePropertyContainer cContainer; // Parse the address return cContainer.ParseRfc822(dwAdrType, ietEncoding, pszRfc822Adr, pList); } // -------------------------------------------------------------------------------- // MimeOleParseRfc822Address // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleParseRfc822AddressW( DWORD dwAdrType, LPCWSTR pwszRfc822Adr, LPADDRESSLIST pList) { // Locals CMimePropertyContainer cContainer; // Parse the address return cContainer.ParseRfc822W(dwAdrType, pwszRfc822Adr, pList); } // -------------------------------------------------------------------------------- // MimeOleGetInternat // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleGetInternat(IMimeInternational **ppInternat) { // check params if (NULL == ppInternat) return TrapError(E_INVALIDARG); // Out of memory if (NULL == g_pInternat) return TrapError(E_OUTOFMEMORY); // Assume Global *ppInternat = (IMimeInternational *)g_pInternat; // Set database (*ppInternat)->AddRef(); // Done return S_OK; } // -------------------------------------------------------------------------------- // MimeOleSplitContentType // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleSplitContentType(LPWSTR pszFull, LPWSTR *ppszCntType, LPWSTR *ppszSubType) { // Locals HRESULT hr = E_FAIL; LPWSTR pszFreeMe = NULL, psz = NULL, pszStart; // check params if (NULL == pszFull) return TrapError(E_INVALIDARG); // Lets dup pszFull to make sure we have read access psz = pszFreeMe = PszDupW(pszFull); if (NULL == psz) { hr = TrapError(E_OUTOFMEMORY); goto exit; } // Find '/' pszStart = psz; while(*psz && *psz != L'/') psz++; // If not found, return if (L'\0' == *psz) goto exit; // Otherwise stuff a null *psz = L'\0'; // Dup *ppszCntType = PszDupW(pszStart); if (NULL == *ppszCntType) { hr = TrapError(E_OUTOFMEMORY); goto exit; } // Step over *psz = L'/'; psz++; // If not found, return if (L'\0' == *psz) goto exit; // Save position pszStart = psz; while(*psz && L';' != *psz) psz++; // Save character... *psz = L'\0'; // Dup as sub type *ppszSubType = PszDupW(pszStart); if (NULL == *ppszSubType) { hr = TrapError(E_OUTOFMEMORY); goto exit; } // Success hr = S_OK; exit: // If failed if (FAILED(hr)) { SafeMemFree((*ppszCntType)); SafeMemFree((*ppszSubType)); } // Cleanup SafeMemFree(pszFreeMe); // Done return hr; } // -------------------------------------------------------------------------------- // MimeEscapeString - quotes '"' and '\' // // Returns S_OK if *ppszOut was allocated and set to the escaped string // Retruns S_FALSE if *ppszOut is NULL - pszIn did not require escaping // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleEscapeString(CODEPAGEID cpiCodePage, LPCSTR pszIn, LPSTR *ppszOut) { // Locals HRESULT hr=S_FALSE; LPSTR pszOut, psz; ULONG cb, c; // check parameters if (NULL == pszIn || NULL == ppszOut) return TrapError(E_INVALIDARG); // $$ INFO $$ This is basically as fast as doing an lstrlen // I've decided to first detect if we need to escape c = 0; cb = 0; psz = (LPSTR)pszIn; while (*psz) { // If DBCS Lead-Byte, then skip if (IsDBCSLeadByteEx(cpiCodePage, *psz)) { cb += 2; psz += 2; } // Otherwise, text for escaped character else { // Count the number of character to escape if ('\"' == *psz || '\\' == *psz || '(' == *psz || ')' == *psz) c++; // Step one more character psz++; cb++; } } // No escape needed if (0 == c) goto exit; // Adjust number of bytes to allocate cb += (c + 1); // worst case - escape every character, so use double original strlen CHECKHR(hr = HrAlloc((LPVOID *)ppszOut, cb)); // Start copy psz = (LPSTR)pszIn; pszOut = *ppszOut; while (*psz) { // If DBCS Lead-Byte, then skip if (IsDBCSLeadByteEx(cpiCodePage, *psz)) { *pszOut++ = *psz++; *pszOut++ = *psz++; } // Otherwise, non-DBCS else { // Do escape if ('\"' == *psz || '\\' == *psz || '(' == *psz || ')' == *psz) *pszOut++ = '\\'; // Regular char *pszOut++ = *psz++; } } // Null term *pszOut = '\0'; exit: // Done return hr; } MIMEOLEAPI MimeOleUnEscapeStringInPlace(LPSTR pszIn) { HRESULT hr = S_OK; ULONG cchOffset = 0; ULONG i = 0; IF_TRUEEXIT((pszIn == NULL), E_INVALIDARG); for(;;i++) { if((pszIn[i + cchOffset] == '\\') && (pszIn[i + cchOffset + 1] == '\\' || pszIn[i + cchOffset + 1] == '\"' || pszIn[i + cchOffset + 1] == '(' || pszIn[i + cchOffset + 1] == ')')) cchOffset++; pszIn[i] = pszIn[i + cchOffset]; if(pszIn[i] == 0) break; } exit: return hr; } // -------------------------------------------------------------------------------- // MimeEscapeString - quotes '"' and '\' // // Returns S_OK if *ppszOut was allocated and set to the escaped string // Retruns S_FALSE if *ppszOut is NULL - pszIn did not require escaping // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleEscapeStringW(LPCWSTR pszIn, LPWSTR *ppszOut) { // Locals HRESULT hr=S_FALSE; LPWSTR pszOut; LPWSTR psz; ULONG cch; ULONG cchExtra; // check parameters if (NULL == pszIn || NULL == ppszOut) return TrapError(E_INVALIDARG); // $$ INFO $$ This is basically as fast as doing an lstrlen // I've decided to first detect if we need to escape cchExtra = 0; cch = 0; psz = (LPWSTR)pszIn; while (*psz) { // Count the number of character to escape if (L'\"' == *psz || L'\\' == *psz || L'(' == *psz || L')' == *psz) cchExtra++; // Step one more character psz++; cch++; } // No escape needed if (0 == cchExtra) goto exit; // Adjust number of bytes to allocate cch += (cchExtra + 1); // worst case - escape every character, so use double original strlen CHECKHR(hr = HrAlloc((LPVOID *)ppszOut, cch * sizeof(WCHAR))); // Start copy psz = (LPWSTR)pszIn; pszOut = *ppszOut; while (*psz) { // Do escape if (L'\"' == *psz || L'\\' == *psz || L'(' == *psz || L')' == *psz) *pszOut++ = L'\\'; // Regular char *pszOut++ = *psz++; } // Null term *pszOut = L'\0'; exit: // Done return hr; } // -------------------------------------------------------------------------------- // MimeOleGetFileExtension // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleGetFileExtension(LPCSTR pszFilePath, LPSTR pszExt, ULONG cchMax) { // Locals CHAR *pszExtT; // Invalid Arg if (NULL == pszFilePath || NULL == pszExt || cchMax < _MAX_EXT) return TrapError(E_INVALIDARG); // Locate the extension of the file pszExtT = PathFindExtension(pszFilePath); StrCpyN(pszExt, pszExtT, cchMax); // Done return S_OK; } // -------------------------------------------------------------------------------- // MimeOleGetExtClassId // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleGetExtClassId(LPCSTR pszExtension, LPCLSID pclsid) { // Locals HRESULT hr=S_OK; ULONG cb; LPSTR pszCLSID=NULL; HKEY hkeyExt=NULL; HKEY hkeyCLSID=NULL; LPSTR pszData=NULL; LPWSTR pwszCLSID=NULL; // check params if (NULL == pszExtension || NULL == pclsid) return TrapError(E_INVALIDARG); // Otherwise, lets lookup the extension in HKEY_CLASSESS_ROOT if (RegOpenKeyEx(HKEY_CLASSES_ROOT, pszExtension, 0, KEY_READ, &hkeyExt) != ERROR_SUCCESS) { hr = MIME_E_NOT_FOUND; goto exit; } // Query Value if (RegQueryValueEx(hkeyExt, NULL, 0, NULL, NULL, &cb) != ERROR_SUCCESS) { hr = MIME_E_NOT_FOUND; goto exit; } // Allocate Size cb += 1; CHECKHR(hr = HrAlloc((LPVOID *)&pszData, cb)); // Get the data if (RegQueryValueEx(hkeyExt, NULL, 0, NULL, (LPBYTE)pszData, &cb) != ERROR_SUCCESS) { hr = TrapError(E_FAIL); goto exit; } // Close this regkey RegCloseKey(hkeyExt); hkeyExt = NULL; // Otherwise, lets lookup the extension in HKEY_CLASSESS_ROOT if (RegOpenKeyEx(HKEY_CLASSES_ROOT, pszData, 0, KEY_READ, &hkeyExt) != ERROR_SUCCESS) { hr = MIME_E_NOT_FOUND; goto exit; } // Otherwise, lets lookup the extension in HKEY_CLASSESS_ROOT if (RegOpenKeyEx(hkeyExt, c_szCLSID, 0, KEY_READ, &hkeyCLSID) != ERROR_SUCCESS) { hr = MIME_E_NOT_FOUND; goto exit; } // Get the data if (RegQueryValueEx(hkeyCLSID, NULL, 0, NULL, NULL, &cb) != ERROR_SUCCESS) { hr = TrapError(E_FAIL); goto exit; } // Add One cb += 1; CHECKHR(hr = HrAlloc((LPVOID *)&pszCLSID, cb)); // Get the data if (RegQueryValueEx(hkeyCLSID, NULL, 0, NULL, (LPBYTE)pszCLSID, &cb) != ERROR_SUCCESS) { hr = TrapError(E_FAIL); goto exit; } // ToUnicode IF_NULLEXIT(pwszCLSID = PszToUnicode(CP_ACP, pszCLSID)); // Convert to class id CHECKHR(hr = CLSIDFromString(pwszCLSID, pclsid)); exit: // Close Reg Keys if (hkeyExt) RegCloseKey(hkeyExt); if (hkeyCLSID) RegCloseKey(hkeyCLSID); SafeMemFree(pszData); SafeMemFree(pwszCLSID); SafeMemFree(pszCLSID); // Done return hr; } // -------------------------------------------------------------------------------- // MimeOleGetExtContentType // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleGetExtContentType(LPCSTR pszExtension, LPSTR *ppszContentType) { LPWSTR pwszExt, pwszContType = NULL; HRESULT hr = S_OK; if (NULL == pszExtension || NULL == ppszContentType || '.' != *pszExtension) return TrapError(E_INVALIDARG); IF_NULLEXIT(pwszExt = PszToUnicode(CP_ACP, pszExtension)); IF_FAILEXIT(hr = MimeOleGetExtContentTypeW(pwszExt, &pwszContType)); IF_NULLEXIT(*ppszContentType = PszToANSI(CP_ACP, pwszContType)); exit: MemFree(pwszExt); MemFree(pwszContType); return hr; } MIMEOLEAPI MimeOleGetExtContentTypeW(LPCWSTR pszExtension, LPWSTR *ppszContentType) { // Locals HRESULT hr=S_OK; ULONG i; HKEY hkeyExt=NULL; LPWSTR pszFull=NULL; ULONG cb; // check params if (NULL == pszExtension || NULL == ppszContentType || '.' != *pszExtension) return TrapError(E_INVALIDARG); // Otherwise, lets lookup the extension in HKEY_CLASSESS_ROOT if (RegOpenKeyExWrapW(HKEY_CLASSES_ROOT, pszExtension, 0, KEY_READ, &hkeyExt) == ERROR_SUCCESS) { // Query Value if (RegQueryValueExWrapW(hkeyExt, c_szContentTypeW, 0, NULL, NULL, &cb) == ERROR_SUCCESS) { // Add One cb += 1; // Allocate Size pszFull = PszAllocW(cb); if (NULL == pszFull) { hr = TrapError(E_OUTOFMEMORY); goto exit; } // Get the data if (RegQueryValueExWrapW(hkeyExt, c_szContentTypeW, 0, NULL, (LPBYTE)pszFull, &cb) == ERROR_SUCCESS) { // Set It *ppszContentType = pszFull; pszFull = NULL; goto exit; } } } // Not found hr = MIME_E_NOT_FOUND; exit: // Close Reg Keys if (hkeyExt) RegCloseKey(hkeyExt); // Cleanup MemFree(pszFull); // Done return hr; } // -------------------------------------------------------------------------------- // MimeOleGetFileInfo // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleGetFileInfo( LPSTR pszFilePath, LPSTR *ppszCntType, LPSTR *ppszSubType, LPSTR *ppszCntDesc, LPSTR *ppszFileName, LPSTR *ppszExtension) { HRESULT hr = S_OK; LPWSTR pwszFilePath, pwszCntType = NULL, pwszSubType = NULL, pwszCntDesc = NULL, pwszFileName = NULL, pwszExtension = NULL; LPSTR pszCntType = NULL, pszSubType = NULL, pszCntDesc = NULL, pszFileName = NULL, pszExtension = NULL; // check params if (NULL == pszFilePath) return TrapError(E_INVALIDARG); IF_NULLEXIT(pwszFilePath = PszToUnicode(CP_ACP, pszFilePath)); // Only pass in parameters for items that IF_FAILEXIT(hr = MimeOleGetFileInfoW(pwszFilePath, ppszCntType ? &pwszCntType : NULL, ppszSubType ? &pwszSubType : NULL, ppszCntDesc ? &pwszCntDesc : NULL, ppszFileName ? &pwszFileName : NULL, ppszExtension ? &pwszExtension : NULL)); if (ppszCntType) { Assert(pwszCntType); IF_NULLEXIT(pszCntType = PszToANSI(CP_ACP, pwszCntType)); } if (ppszSubType) { Assert(pwszSubType); IF_NULLEXIT(pszSubType = PszToANSI(CP_ACP, pwszSubType)); } if (ppszCntDesc) { Assert(pwszCntDesc); IF_NULLEXIT(pszCntDesc = PszToANSI(CP_ACP, pwszCntDesc)); } if (ppszFileName) { Assert(pwszFileName); IF_NULLEXIT(pszFileName = PszToANSI(CP_ACP, pwszFileName)); } if (ppszExtension) { Assert(pwszExtension); IF_NULLEXIT(pszExtension = PszToANSI(CP_ACP, pwszExtension)); } if (ppszCntType) *ppszCntType = pszCntType; if (ppszSubType) *ppszSubType = pszSubType; if (ppszCntDesc) *ppszCntDesc = pszCntDesc; if (ppszFileName) *ppszFileName = pszFileName; if (ppszExtension) *ppszExtension = pszExtension; exit: MemFree(pwszCntType); MemFree(pwszSubType); MemFree(pwszCntDesc); MemFree(pwszFileName); MemFree(pwszExtension); MemFree(pwszFilePath); if (FAILED(hr)) { MemFree(pszCntType); MemFree(pszSubType); MemFree(pszCntDesc); MemFree(pszFileName); MemFree(pszExtension); } return hr; } MIMEOLEAPI MimeOleGetFileInfoW( LPWSTR pszFilePath, LPWSTR *ppszCntType, LPWSTR *ppszSubType, LPWSTR *ppszCntDesc, LPWSTR *ppszFileName, LPWSTR *ppszExtension) { // Locals HRESULT hr=S_OK; SHFILEINFOW rShFileInfo; LPWSTR pszFull=NULL, pszExt, pszFname; // check params if (NULL == pszFilePath) return TrapError(E_INVALIDARG); // Init if (ppszCntType) *ppszCntType = NULL; if (ppszSubType) *ppszSubType = NULL; if (ppszCntDesc) *ppszCntDesc = NULL; if (ppszFileName) *ppszFileName = NULL; if (ppszExtension) *ppszExtension = NULL; // Locate the extension of the file pszFname = PathFindFileNameW(pszFilePath); pszExt = PathFindExtensionW(pszFilePath); // Did the user want the actual filename... if (ppszFileName) { // Allocate *ppszFileName = PszDupW(pszFname); if (NULL == *ppszFileName) { hr = TrapError(E_OUTOFMEMORY); goto exit; } } // Empty extension if (FIsEmptyW(pszExt)) { hr = TrapError(E_FAIL); goto exit; } // User wanted the extension if (ppszExtension) { // Allocate *ppszExtension = PszDupW(pszExt); if (NULL == *ppszExtension) { hr = TrapError(E_OUTOFMEMORY); goto exit; } } // User wanted ppszCntDesc if (ppszCntDesc) { // Lets try to get the extension file information first if (SHGetFileInfoWrapW(pszExt, FILE_ATTRIBUTE_NORMAL, &rShFileInfo, sizeof(rShFileInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_DISPLAYNAME | SHGFI_TYPENAME)) { // Set lppszCntDesc + ( ) DWORD cchSize = (lstrlenW(rShFileInfo.szDisplayName) + lstrlenW(rShFileInfo.szTypeName) + 5); *ppszCntDesc = PszAllocW(cchSize); if (NULL == *ppszCntDesc) { hr = TrapError(E_OUTOFMEMORY); goto exit; } // Format the string wnsprintfW(*ppszCntDesc, cchSize, L"%s, (%s)", rShFileInfo.szDisplayName, rShFileInfo.szTypeName); } } // Content type if (ppszCntType && ppszSubType) { // Lookup content type if (SUCCEEDED(MimeOleGetExtContentTypeW(pszExt, &pszFull))) { // Split content type CHECKHR(hr = MimeOleSplitContentType(pszFull, ppszCntType, ppszSubType)); } } exit: // Set defaults if something was not found... if (ppszCntType && NULL == *ppszCntType) *ppszCntType = PszDupW((LPWSTR)STR_CNT_APPLICATIONW); if (ppszSubType && NULL == *ppszSubType) *ppszSubType = PszDupW((LPWSTR)STR_SUB_OCTETSTREAMW); if (ppszCntDesc && NULL == *ppszCntDesc) *ppszCntDesc = PszDupW((LPWSTR)c_szEmptyW); // Cleanup SafeMemFree(pszFull); // Done return hr; } // -------------------------------------------------------------------------------- // MimeOleGetContentTypeExt // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleGetContentTypeExt(LPCSTR pszContentType, LPSTR *ppszExtension) { // Locals HRESULT hr=S_OK; HKEY hDatabase=NULL; HKEY hContentType=NULL; ULONG cb; // check params if (NULL == pszContentType || NULL == ppszExtension) return TrapError(E_INVALIDARG); // Open Content-Type --> file extension MIME Database registry key if (RegOpenKeyEx(HKEY_CLASSES_ROOT, c_szMDBContentType, 0, KEY_READ, &hDatabase) != ERROR_SUCCESS) { hr = MIME_E_NOT_FOUND; goto exit; } // Open Content Type if (RegOpenKeyEx(hDatabase, pszContentType, 0, KEY_READ, &hContentType) != ERROR_SUCCESS) { hr = MIME_E_NOT_FOUND; goto exit; } // Query for size if (RegQueryValueEx(hContentType, c_szExtension, 0, NULL, NULL, &cb) != ERROR_SUCCESS) { hr = MIME_E_NOT_FOUND; goto exit; } // Allocate It *ppszExtension = PszAllocA(cb + 1); if (NULL == *ppszExtension) { hr = TrapError(E_OUTOFMEMORY); goto exit; } // Query for extension cb = cb + 1; if (RegQueryValueEx(hContentType, c_szExtension, 0, NULL, (LPBYTE)*ppszExtension, &cb) != ERROR_SUCCESS) { hr = TrapError(E_FAIL); goto exit; } exit: // Cleanup if (hContentType) RegCloseKey(hContentType); if (hDatabase) RegCloseKey(hDatabase); // Done return hr; } // -------------------------------------------------------------------------------- // MimeOleFindCharset // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleFindCharset(LPCSTR pszCharset, LPHCHARSET phCharset) { Assert(g_pInternat); return g_pInternat->FindCharset(pszCharset, phCharset); } // -------------------------------------------------------------------------------- // MimeOleGetCharsetInfo // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleGetCharsetInfo(HCHARSET hCharset, LPINETCSETINFO pCsetInfo) { Assert(g_pInternat); return g_pInternat->GetCharsetInfo(hCharset, pCsetInfo); } // -------------------------------------------------------------------------------- // MimeOleGetCodePageInfo // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleGetCodePageInfo(CODEPAGEID cpiCodePage, LPCODEPAGEINFO pCodePageInfo) { Assert(g_pInternat); return g_pInternat->GetCodePageInfo(cpiCodePage, pCodePageInfo); } // -------------------------------------------------------------------------------- // MimeOleGetDefaultCharset // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleGetDefaultCharset(LPHCHARSET phCharset) { Assert(g_pInternat); return g_pInternat->GetDefaultCharset(phCharset); } // -------------------------------------------------------------------------------- // MimeOleSetDefaultCharset // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleSetDefaultCharset(HCHARSET hCharset) { Assert(g_pInternat); return g_pInternat->SetDefaultCharset(hCharset); } // -------------------------------------------------------------------------------- // MimeOleGetCodePageCharset // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleGetCodePageCharset(CODEPAGEID cpiCodePage, CHARSETTYPE ctCsetType, LPHCHARSET phCharset) { Assert(g_pInternat); return g_pInternat->GetCodePageCharset(cpiCodePage, ctCsetType, phCharset); } // -------------------------------------------------------------------------------- // MimeOleEncodeHeader // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleEncodeHeader( HCHARSET hCharset, LPPROPVARIANT pData, LPSTR *ppszEncoded, LPRFC1522INFO pRfc1522Info) { Assert(g_pInternat); return g_pInternat->EncodeHeader(hCharset, pData, ppszEncoded, pRfc1522Info); } // -------------------------------------------------------------------------------- // MimeOleDecodeHeader // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleDecodeHeader( HCHARSET hCharset, LPCSTR pszData, LPPROPVARIANT pDecoded, LPRFC1522INFO pRfc1522Info) { Assert(g_pInternat); return g_pInternat->DecodeHeader(hCharset, pszData, pDecoded, pRfc1522Info); } // -------------------------------------------------------------------------------- // MimeOleVariantFree // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleVariantFree(LPPROPVARIANT pProp) { // Locals HRESULT hr=S_OK; // Invalid Arg Assert(pProp); // Handle Variant Type... switch(pProp->vt) { case VT_NULL: case VT_EMPTY: case VT_ILLEGAL: case VT_UI1: case VT_I2: case VT_UI2: case VT_I4: case VT_UI4: case VT_I8: case VT_UI8: case VT_R4: case VT_R8: case VT_CY: case VT_DATE: case VT_BOOL: case VT_ERROR: case VT_FILETIME: break; case VT_CF: case VT_CLSID: case VT_LPWSTR: case VT_LPSTR: if ((LPVOID)pProp->pszVal != NULL) MemFree((LPVOID)pProp->pszVal); break; case VT_BLOB: if (pProp->blob.pBlobData) MemFree(pProp->blob.pBlobData); break; case VT_STREAM: if (pProp->pStream) pProp->pStream->Release(); break; case VT_STORAGE: if (pProp->pStorage) pProp->pStorage->Release(); break; default: Assert(FALSE); hr = TrapError(E_INVALIDARG); break; } // Init MimeOleVariantInit(pProp); // Done return hr; } // -------------------------------------------------------------------------------- // MimeOleVariantCopy // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleVariantCopy(LPPROPVARIANT pDest, LPPROPVARIANT pSource) { // Locals HRESULT hr=S_OK; ULONG cb; // Invalid Arg Assert(pSource && pDest); // Handle Variant Type... switch(pSource->vt) { case VT_UI1: pDest->bVal = pSource->bVal; break; case VT_I2: pDest->iVal= pSource->iVal; break; case VT_UI2: pDest->uiVal = pSource->uiVal; break; case VT_I4: pDest->lVal = pSource->lVal; break; case VT_UI4: pDest->ulVal = pSource->ulVal; break; case VT_I8: pDest->hVal.QuadPart = pSource->hVal.QuadPart; break; case VT_UI8: pDest->uhVal.QuadPart = pSource->uhVal.QuadPart; break; case VT_R4: pDest->fltVal = pSource->fltVal; break; case VT_R8: pDest->dblVal = pSource->dblVal; break; case VT_CY: CopyMemory(&pDest->cyVal, &pSource->cyVal, sizeof(CY)); break; case VT_DATE: pDest->date = pSource->date; break; case VT_BOOL: pDest->boolVal = pSource->boolVal; break; case VT_ERROR: pDest->scode = pSource->scode; break; case VT_FILETIME: CopyMemory(&pDest->filetime, &pSource->filetime, sizeof(FILETIME)); break; case VT_CF: // Invalid Arg if (NULL == pSource->pclipdata) return TrapError(E_INVALIDARG); // Duplicate the clipboard format CHECKALLOC(pDest->pclipdata = (CLIPDATA *)g_pMalloc->Alloc(sizeof(CLIPDATA))); // Copy the data CopyMemory(pDest->pclipdata, pSource->pclipdata, sizeof(CLIPDATA)); break; case VT_CLSID: // Invalid Arg if (NULL == pDest->puuid) return TrapError(E_INVALIDARG); // Duplicate the CLSID CHECKALLOC(pDest->puuid = (CLSID *)g_pMalloc->Alloc(sizeof(CLSID))); // Copy CopyMemory(pDest->puuid, pSource->puuid, sizeof(CLSID)); break; case VT_LPWSTR: // Invalid Arg if (NULL == pSource->pwszVal) return TrapError(E_INVALIDARG); // Get Size cb = (lstrlenW(pSource->pwszVal) + 1) * sizeof(WCHAR); // Dup the unicode String CHECKALLOC(pDest->pwszVal = (LPWSTR)g_pMalloc->Alloc(cb)); // Copy the data CopyMemory(pDest->pwszVal, pSource->pwszVal, cb); break; case VT_LPSTR: // Invalid Arg if (NULL == pSource->pszVal) return TrapError(E_INVALIDARG); // Get Size cb = lstrlen(pSource->pszVal) + 1; // Dup the unicode String CHECKALLOC(pDest->pszVal = (LPSTR)g_pMalloc->Alloc(cb)); // Copy the data CopyMemory(pDest->pszVal, pSource->pszVal, cb); break; case VT_BLOB: // Invalid Arg if (NULL == pSource->blob.pBlobData) return TrapError(E_INVALIDARG); // Duplicate the blob CHECKALLOC(pDest->blob.pBlobData = (LPBYTE)g_pMalloc->Alloc(pSource->blob.cbSize)); // Copy the data CopyMemory(pDest->blob.pBlobData, pSource->blob.pBlobData, pSource->blob.cbSize); break; case VT_STREAM: // Invalid Arg if (NULL == pSource->pStream) return TrapError(E_INVALIDARG); // Assume the new stream pDest->pStream = pSource->pStream; pDest->pStream->AddRef(); break; case VT_STORAGE: // Invalid Arg if (NULL == pSource->pStorage) return TrapError(E_INVALIDARG); // Assume the new storage pDest->pStorage = pSource->pStorage; pDest->pStorage->AddRef(); break; default: Assert(FALSE); hr = TrapError(E_INVALIDARG); goto exit; } // Success, return vt pDest->vt = pSource->vt; exit: // Done return hr; } // -------------------------------------------------------------------------------- // MimeOleRecurseSetProp // -------------------------------------------------------------------------------- HRESULT MimeOleRecurseSetProp(IMimeMessageTree *pTree, HBODY hBody, LPCSTR pszName, DWORD dwFlags, LPCPROPVARIANT pValue) { // Locals HRESULT hr=S_OK; HRESULT hrFind; HBODY hChild; // Invalid Arg Assert(pTree && hBody && pValue); // multipart/alternative if (pTree->IsContentType(hBody, STR_CNT_MULTIPART, NULL) == S_OK) { // Get First Child hrFind = pTree->GetBody(IBL_FIRST, hBody, &hChild); while(SUCCEEDED(hrFind) && hChild) { // Go down to the child CHECKHR(hr = MimeOleRecurseSetProp(pTree, hChild, pszName, dwFlags, pValue)); // Next Child hrFind = pTree->GetBody(IBL_NEXT, hChild, &hChild); } } // Otherwise else { // Go down to the child CHECKHR(hr = pTree->SetBodyProp(hBody, pszName, dwFlags, pValue)); } exit: // Done return hr; } // -------------------------------------------------------------------------------- // MimeOleGetPropA // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleGetPropA( IMimePropertySet *pPropertySet, LPCSTR pszName, DWORD dwFlags, LPSTR *ppszData) { // Locals HRESULT hr=S_OK; // Invaid Arg if (NULL == pPropertySet) return TrapError(E_INVALIDARG); // Initialzie PropVariant PROPVARIANT rVariant; rVariant.vt = VT_LPSTR; // Call Method CHECKHR(hr = pPropertySet->GetProp(pszName, dwFlags, &rVariant)); // Return the Data *ppszData = rVariant.pszVal; exit: // Done return hr; } // -------------------------------------------------------------------------------- // MimeOleSetPropA // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleSetPropA( IMimePropertySet *pPropertySet, LPCSTR pszName, DWORD dwFlags, LPCSTR pszData) { // Invaid Arg if (NULL == pPropertySet) return TrapError(E_INVALIDARG); // Initialzie PropVariant PROPVARIANT rVariant; rVariant.vt = VT_LPSTR; rVariant.pszVal = (LPSTR)pszData; // Call Method return TrapError(pPropertySet->SetProp(pszName, dwFlags, &rVariant)); } // -------------------------------------------------------------------------------- // MimeOleGetPropW // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleGetPropW( IMimePropertySet *pPropertySet, LPCSTR pszName, DWORD dwFlags, LPWSTR *ppszData) { // Locals HRESULT hr=S_OK; // Invaid Arg if (NULL == pPropertySet) return TrapError(E_INVALIDARG); // Initialzie PropVariant PROPVARIANT rVariant; rVariant.vt = VT_LPWSTR; // Call Method CHECKHR(hr = pPropertySet->GetProp(pszName, dwFlags, &rVariant)); // Return the Data *ppszData = rVariant.pwszVal; exit: // Done return hr; } // -------------------------------------------------------------------------------- // MimeOleSetPropW // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleSetPropW( IMimePropertySet *pPropertySet, LPCSTR pszName, DWORD dwFlags, LPWSTR pszData) { // Invaid Arg if (NULL == pPropertySet) return TrapError(E_INVALIDARG); // Initialzie PropVariant PROPVARIANT rVariant; rVariant.vt = VT_LPWSTR; rVariant.pwszVal = (LPWSTR)pszData; // Call Method return TrapError(pPropertySet->SetProp(pszName, dwFlags, &rVariant)); } // -------------------------------------------------------------------------------- // MimeOleGetBodyPropA // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleGetBodyPropA( IMimeMessageTree *pTree, HBODY hBody, LPCSTR pszName, DWORD dwFlags, LPSTR *ppszData) { // Locals HRESULT hr=S_OK; // Invaid Arg if (NULL == pTree) return TrapError(E_INVALIDARG); // Initialzie PropVariant PROPVARIANT rVariant; rVariant.vt = VT_LPSTR; // Call Method CHECKHR(hr = pTree->GetBodyProp(hBody, pszName, dwFlags, &rVariant)); // Return the Data *ppszData = rVariant.pszVal; exit: // Done return hr; } // -------------------------------------------------------------------------------- // MimeOleSetBodyPropA // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleSetBodyPropA( IMimeMessageTree *pTree, HBODY hBody, LPCSTR pszName, DWORD dwFlags, LPCSTR pszData) { // Invaid Arg if (NULL == pTree) return TrapError(E_INVALIDARG); // Initialzie PropVariant PROPVARIANT rVariant; rVariant.vt = VT_LPSTR; rVariant.pszVal = (LPSTR)pszData; // Call Method return TrapError(pTree->SetBodyProp(hBody, pszName, dwFlags, &rVariant)); } // -------------------------------------------------------------------------------- // MimeOleGetBodyPropW // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleGetBodyPropW( IMimeMessageTree *pTree, HBODY hBody, LPCSTR pszName, DWORD dwFlags, LPWSTR *ppszData) { // Locals HRESULT hr=S_OK; // Invaid Arg if (NULL == pTree) return TrapError(E_INVALIDARG); // Initialzie PropVariant PROPVARIANT rVariant; rVariant.vt = VT_LPWSTR; // Call Method CHECKHR(hr = pTree->GetBodyProp(hBody, pszName, dwFlags, &rVariant)); // Return the Data *ppszData = rVariant.pwszVal; exit: // Done return hr; } // -------------------------------------------------------------------------------- // MimeOleSetBodyPropW // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleSetBodyPropW( IMimeMessageTree *pTree, HBODY hBody, LPCSTR pszName, DWORD dwFlags, LPCWSTR pszData) { // Invaid Arg if (NULL == pTree) return TrapError(E_INVALIDARG); // Initialzie PropVariant PROPVARIANT rVariant; rVariant.vt = VT_LPWSTR; rVariant.pwszVal = (LPWSTR)pszData; // Call Method return TrapError(pTree->SetBodyProp(hBody, pszName, dwFlags, &rVariant)); } // -------------------------------------------------------------------------------- // MimeOleQueryString // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleQueryString( LPCSTR pszSearchMe, LPCSTR pszCriteria, boolean fSubString, boolean fCaseSensitive) { // Locals HRESULT hr=S_OK; LPSTR pszDataLower=NULL; // Invalid Arg Assert(pszSearchMe && pszCriteria); // Init STACKSTRING_DEFINE(rDataLower, 255); // No SubString Search if (FALSE == fSubString) { // Case Sensitive if (fCaseSensitive) { // Equal if (lstrcmp(pszSearchMe, pszCriteria) == 0) goto exit; } // Otherwise, Not Case Sensitive else if (lstrcmpi(pszSearchMe, pszCriteria) == 0) goto exit; } // Otheriwse, comparing substring else { // Case Sensitive if (fCaseSensitive) { // Equal if (StrStr(pszSearchMe, pszCriteria) != NULL) goto exit; } // Otherwise, Not Case Sensitive else { // Get the Length ULONG cchSearchMe = lstrlen(pszSearchMe); // Set size the stack string STACKSTRING_SETSIZE(rDataLower, cchSearchMe + 1); // Copy the data CopyMemory(rDataLower.pszVal, pszSearchMe, cchSearchMe + 1); // Lower Case Compare CharLower(rDataLower.pszVal); // Compare Strings... if (StrStr(rDataLower.pszVal, pszCriteria) != NULL) goto exit; } } // No Match hr = S_FALSE; exit: // Cleanup STACKSTRING_FREE(rDataLower); // Done return hr; } // -------------------------------------------------------------------------------- // MimeOleQueryStringW // -------------------------------------------------------------------------------- HRESULT MimeOleQueryStringW(LPCWSTR pszSearchMe, LPCWSTR pszCriteria, boolean fSubString, boolean fCaseSensitive) { // Locals HRESULT hr=S_OK; // Invalid Arg Assert(pszSearchMe && pszCriteria); // No SubString Search if (FALSE == fSubString) { // Case Sensitive if (fCaseSensitive) { // Equal if (StrCmpW(pszSearchMe, pszCriteria) == 0) goto exit; } // Otherwise, Not Case Sensitive else if (StrCmpIW(pszSearchMe, pszCriteria) == 0) goto exit; } // Otheriwse, comparing substring else { // Case Sensitive if (fCaseSensitive) { // Equal if (StrStrW(pszSearchMe, pszCriteria) != NULL) goto exit; } // Otherwise, Not Case Sensitive else if (StrStrIW(pszSearchMe, pszCriteria) != NULL) goto exit; } // No Match hr = S_FALSE; exit: // Done return hr; } #define FILETIME_SECOND 10000000 // 100ns intervals per second LONG CertVerifyTimeValidityWithDelta(LPFILETIME pTimeToVerify, PCERT_INFO pCertInfo, ULONG ulOffset) { LONG lRet; FILETIME ftNow; __int64 i64Offset; #ifdef WIN32 union { FILETIME ftDelta; __int64 i64Delta; }; #else // FILETIME ftDelta; // __int64 i64Delta; // // WIN32 specific. I've commented this for WIN32 so that it will produce a compilation // error on non Win32 platforms. The following code is specific to i386 since it relies on // __int64 being stored low dword first. // // I would have used right shift by 32 but it is not in iert.lib Maybe you unix and mac folks // can get it in there. On the other hand, maybe you won't need to. #endif lRet = CertVerifyTimeValidity(pTimeToVerify, pCertInfo); if (lRet < 0) { if (! pTimeToVerify) { // Get the current time in filetime format so we can add the offset GetSystemTimeAsFileTime(&ftNow); pTimeToVerify = &ftNow; } i64Delta = pTimeToVerify->dwHighDateTime; i64Delta = i64Delta << 32; i64Delta += pTimeToVerify->dwLowDateTime; // Add the offset into the original time to get us a new time to check i64Offset = FILETIME_SECOND; i64Offset *= ulOffset; i64Delta += i64Offset; // ftDelta.dwLowDateTime = (ULONG)i64Delta & 0xFFFFFFFF; // ftDelta.dwHighDateTime = (ULONG)(i64Delta >> 32); lRet = CertVerifyTimeValidity(&ftDelta, pCertInfo); } return(lRet); } /* GetCertsFromThumbprints: ** ** Purpose: ** Given a set of thumbprints, return an equivalent set of certificates. ** Takes: ** IN rgThumbprint - array of thumbprints to lookup ** INOUT pResults - the hr array contains error info for each cert ** lookup. The pCert array has the certs. ** cEntries must be set on IN ** arrays must be alloc'd on IN ** IN rghCertStore - set of stores to search ** IN cCertStore - size of rghCertStore ** Returns: ** MIME_S_SECURITY_ERROROCCURED if any of the lookups fail ** (CERTIFICATE_NOT_PRESENT in the cs array for such cases) ** MIME_S_SECURITY_NOOP if you call it with 0 in cEntries ** E_INVALIDARG if any of the parameters are null ** S_OK implies that all certs were found ** Note: ** only indexes with non-null thumbprints are considered */ MIMEOLEAPI MimeOleGetCertsFromThumbprints( THUMBBLOB *const rgThumbprint, X509CERTRESULT *const pResults, const HCERTSTORE *const rghCertStore, const DWORD cCertStore) { HRESULT hr; ULONG iEntry, iStore; if (!(rgThumbprint && pResults && pResults->rgpCert && pResults->rgcs && rghCertStore && cCertStore)) { hr = TrapError(E_INVALIDARG); goto exit; } if (0 == pResults->cEntries) { hr = MIME_S_SECURITY_NOOP; goto exit; } hr = S_OK; for (iEntry = 0; iEntry < pResults->cEntries; iEntry++) { if (rgThumbprint[iEntry].pBlobData) { for (iStore = 0; iStore < cCertStore; iStore++) { // We have a thumbprint, so do lookup pResults->rgpCert[iEntry] = CertFindCertificateInStore(rghCertStore[iStore], X509_ASN_ENCODING, 0, //dwFindFlags CERT_FIND_HASH, (void *)(CRYPT_DIGEST_BLOB *)&(rgThumbprint[iEntry]), NULL); if (pResults->rgpCert[iEntry]) { break; } } if (!pResults->rgpCert[iEntry]) { DOUTL(1024, "CRYPT: Cert lookup failed. #%d", iEntry); pResults->rgcs[iEntry] = CERTIFICATE_NOT_PRESENT; hr = MIME_S_SECURITY_ERROROCCURED; } else { // Validity check if (0 != CertVerifyTimeValidityWithDelta(NULL, PCCERT_CONTEXT(pResults->rgpCert[iEntry])->pCertInfo, TIME_DELTA_SECONDS)) { pResults->rgcs[iEntry] = CERTIFICATE_EXPIRED; } else { pResults->rgcs[iEntry] = CERTIFICATE_OK; } } } else { CRDOUT("For want of a thumbprint... #%d", iEntry); pResults->rgpCert[iEntry] = NULL; pResults->rgcs[iEntry] = CERTIFICATE_NOPRINT; hr = MIME_S_SECURITY_ERROROCCURED; } } exit: return hr; } // -------------------------------------------------------------------------------- // MimeOleMapSpecialCodePage // -------------------------------------------------------------------------------- HRESULT MimeOleMapSpecialCodePage(CODEPAGEID cpIn, BOOL fRead, CODEPAGEID *pcpOut) { // Locals DWORD i; INETCSETINFO CsetInfo; // Trace TraceCall("MimeOleMapSpecialCodePage"); // Invalid Args if (NULL == pcpOut) return(TraceResult(E_INVALIDARG)); // Initialize *pcpOut = cpIn; // Walk through the non-standard codepages list for (i=0; OENonStdCPs[i].Codepage != 0; i++) { // Is this it? if (OENonStdCPs[i].Codepage == cpIn) { // Read ? if (fRead && OENonStdCPs[i].cpRead) *pcpOut = OENonStdCPs[i].cpRead; // Send ? else if (OENonStdCPs[i].cpSend) *pcpOut = OENonStdCPs[i].cpSend; // Done break; } } // Done return(S_OK); } // -------------------------------------------------------------------------------- // MimeOleMapCodePageToCharset // -------------------------------------------------------------------------------- HRESULT MimeOleMapCodePageToCharset(CODEPAGEID cpIn, LPHCHARSET phCharset) { // Locals HRESULT hr=S_OK; LPSTR pszCharset; CODEPAGEINFO CodePage; // Trace TraceCall("MimeOleMapCodePageToCharset"); // Invalid Args if (NULL == phCharset) return(TraceResult(E_INVALIDARG)); // Get codepage info IF_FAILEXIT(hr = MimeOleGetCodePageInfo(cpIn, &CodePage)); // Default to using the body charset pszCharset = CodePage.szBodyCset; // Use WebCharset if body charset starts with '_' and the codepage is not 949 if (*CodePage.szBodyCset != '_' && 949 != CodePage.cpiCodePage) pszCharset = CodePage.szWebCset; // Find the Charset IF_FAILEXIT(hr = MimeOleFindCharset(pszCharset, phCharset)); exit: // Done return(hr); } // -------------------------------------------------------------------------------- // MimeOleSplitMessage // -------------------------------------------------------------------------------- MIMEOLEAPI MimeOleSplitMessage(IMimeMessage *pMessage, ULONG cbMaxPart, IMimeMessageParts **ppParts) { // Locals HRESULT hr=S_OK; ULONG cbMessage, cbHeader, cParts, iPart, cbActual, cbRead=0, cAttach, i, cbSubjectAddOn, cbSubjectNew; LPHBODY prghAttach=NULL; IStream *pstmMsg=NULL, *pstmPart=NULL; ULARGE_INTEGER ulicbHeader; IMimePropertySet *pRootProps=NULL; CMimeMessageParts *pParts=NULL; IMimeMessage *pmsgPart=NULL; FILETIME ft; SYSTEMTIME st; CHAR szMimeId[CCHMAX_MID], szNumber[30], szFormat[50]; MIMESAVETYPE savetype; BODYOFFSETS rOffsets; IMimeBody *pRootBody=NULL; LPSTR pszSubjectAddOn=NULL, pszSubjectNew=NULL; PROPVARIANT rVariant, rSubject, rFileName; float dParts; HCHARSET hCharset=NULL; INETCSETINFO CsetInfo; // Invalid Arg if (NULL == ppParts) return TrapError(E_INVALIDARG); // Initialize Variants MimeOleVariantInit(&rSubject); MimeOleVariantInit(&rFileName); // Init *ppParts = NULL; // Get Option rVariant.vt = VT_UI4; pMessage->GetOption(OID_SAVE_FORMAT, &rVariant); savetype = (MIMESAVETYPE)rVariant.ulVal; // Raid-73119: OE : Kor: the charset for the message sent in broken apart is shown as "_autodetect_kr" if (SUCCEEDED(pMessage->GetCharset(&hCharset))) { // Get the charset info for the HCHARSET if (SUCCEEDED(MimeOleGetCharsetInfo(hCharset, &CsetInfo))) { // Map the codepage CODEPAGEID cpActual; // Map the codepage to the correct codepage.. if (SUCCEEDED(MimeOleMapSpecialCodePage(CsetInfo.cpiInternet, FALSE, &cpActual))) { // If Different if (cpActual != CsetInfo.cpiInternet) { // Map the codepage to a character set MimeOleMapCodePageToCharset(cpActual, &hCharset); // Reset the character set.... SideAssert(SUCCEEDED(pMessage->SetCharset(hCharset, CSET_APPLY_TAG_ALL))); } } } } // Get Message Source CHECKHR(hr = pMessage->GetMessageSource(&pstmMsg, COMMIT_ONLYIFDIRTY)); // Create Parts Object CHECKALLOC(pParts = new CMimeMessageParts); // Rewind the stream CHECKHR(hr = HrRewindStream(pstmMsg)); // Get Stream Size CHECKHR(hr = HrSafeGetStreamSize(pstmMsg, &cbMessage)); // Is this size larger than the max part size if (cbMessage <= cbMaxPart) { // Add Single Parts to parts object CHECKHR(hr = pParts->AddPart(pMessage)); // Done goto exit; } // Get the root body CHECKHR(hr = pMessage->BindToObject(HBODY_ROOT, IID_IMimeBody, (LPVOID *)&pRootBody)); // Get Root body offset info CHECKHR(hr = pRootBody->GetOffsets(&rOffsets)); // If the header is bigger than the max message size, we have a problem cbHeader = (ULONG)rOffsets.cbBodyStart - rOffsets.cbHeaderStart; if (cbHeader >= cbMessage || cbHeader + 256 >= cbMaxPart) { AssertSz(FALSE, "SplitMessage: The header is bigger than the max message size"); hr = TrapError(MIME_E_MAX_SIZE_TOO_SMALL); goto exit; } // Get a copy of the root header CHECKHR(hr = pRootBody->Clone(&pRootProps)); // Lets cleanup this header... pRootProps->DeleteProp(PIDTOSTR(PID_HDR_CNTTYPE)); pRootProps->DeleteProp(PIDTOSTR(PID_HDR_CNTDISP)); pRootProps->DeleteProp(PIDTOSTR(PID_HDR_CNTDESC)); pRootProps->DeleteProp(PIDTOSTR(PID_HDR_CNTID)); pRootProps->DeleteProp(PIDTOSTR(PID_HDR_CNTLOC)); pRootProps->DeleteProp(PIDTOSTR(PID_HDR_MIMEVER)); pRootProps->DeleteProp(PIDTOSTR(PID_HDR_CNTXFER)); pRootProps->DeleteProp("Disposition-Notification-To"); pRootProps->DeleteProp(PIDTOSTR(PID_HDR_MESSAGEID)); // Compute the number of parts as a float dParts = (float)((float)cbMessage / (float)(cbMaxPart - cbHeader)); // If dParts is not an integer, round up. cParts = (dParts - ((ULONG)dParts)) ? ((ULONG)dParts) + 1 : ((ULONG)dParts); // Set Max Parts in parts object CHECKHR(hr = pParts->SetMaxParts(cParts)); // If MIME, create id if (SAVE_RFC1521 == savetype) { // Create Mime Id GetSystemTime(&st); SystemTimeToFileTime(&st, &ft); wnsprintfA(szMimeId, ARRAYSIZE(szMimeId), "%08.8lX.%08.8lX@%s", ft.dwHighDateTime, ft.dwLowDateTime, (LPSTR)SzGetLocalHostName()); // total=X wnsprintfA(szNumber, ARRAYSIZE(szNumber), "%d", cParts); // number=x rVariant.vt = VT_LPSTR; rVariant.pszVal = szNumber; CHECKHR(hr = pRootProps->SetProp(STR_PAR_TOTAL, 0, &rVariant)); // id=XXXX rVariant.pszVal = szMimeId; CHECKHR(hr = pRootProps->SetProp(STR_PAR_ID, 0, &rVariant)); // MIME Version rVariant.pszVal = (LPSTR)c_szMimeVersion; CHECKHR(hr = pRootProps->SetProp(PIDTOSTR(PID_HDR_MIMEVER), 0, &rVariant)); } // Otherwise, seek pstmMsg to end of header else { // Get Stream Position CHECKHR(hr = HrStreamSeekSet(pstmMsg, rOffsets.cbBodyStart)); // Reduce the message size cbMessage -= rOffsets.cbBodyStart; } // Init the variant rSubject.vt = VT_LPSTR; // Get Subject if (FAILED(pRootBody->GetProp(PIDTOSTR(PID_HDR_SUBJECT), 0, &rSubject))) rSubject.pszVal = NULL; // Enumerate bodies and get the first file name and use it in the new subject... if (SUCCEEDED(pMessage->GetAttachments(&cAttach, &prghAttach))) { // Init the variant rFileName.vt = VT_LPSTR; // Loop Attached for (i=0; iGetBodyProp(prghAttach[i], PIDTOSTR(PID_ATT_FILENAME), 0, &rFileName))) break; } } // Format Number wnsprintfA(szNumber, ARRAYSIZE(szNumber), "%d", cParts); // Have a file name if (rFileName.pszVal) { // Make Format String... wnsprintfA(szFormat, ARRAYSIZE(szFormat), "%%s [%%0%dd/%d]", lstrlen(szNumber), cParts); // Size of subject add on string cbSubjectAddOn = lstrlen(rFileName.pszVal) + lstrlen(szFormat) + lstrlen(szNumber) + 1; } // Otherwise, no filename else { // Make Format String... wnsprintfA(szFormat, ARRAYSIZE(szFormat), "[%%0%dd/%d]", lstrlen(szNumber), cParts); // Size of subject add on string cbSubjectAddOn = lstrlen(szFormat) + lstrlen(szNumber) + 1; } // Allocate Subject Add On DWORD cchSize = (cbSubjectAddOn / sizeof(pszSubjectAddOn[0])); CHECKALLOC(pszSubjectAddOn = PszAllocA(cchSize)); // Allocate new subject if (rSubject.pszVal) cbSubjectNew = cbSubjectAddOn + lstrlen(rSubject.pszVal) + 5; else cbSubjectNew = cbSubjectAddOn + 5; // Allocate Subject New CHECKALLOC(pszSubjectNew = PszAllocA(cbSubjectNew)); // Loop throught the number of parts for (iPart=0; iPartSetProp(PIDTOSTR(PID_HDR_CNTTYPE), 0, &rVariant)); // number=X wnsprintfA(szNumber, ARRAYSIZE(szNumber), "%d", iPart+1); rVariant.pszVal = szNumber; CHECKHR(hr = pRootProps->SetProp(STR_PAR_NUMBER, 0, &rVariant)); } // Build Subject AddOn if (rFileName.pszVal) wnsprintfA(pszSubjectAddOn, cchSize, szFormat, rFileName.pszVal, iPart + 1); else wnsprintfA(pszSubjectAddOn, cchSize, szFormat, iPart + 1); // Build New Subject if (rSubject.pszVal) wnsprintfA(pszSubjectNew, cbSubjectNew, "%s %s", rSubject.pszVal, pszSubjectAddOn); else wnsprintfA(pszSubjectNew, cbSubjectNew, "%s", pszSubjectAddOn); // Set New Subject rVariant.vt = VT_LPSTR; rVariant.pszVal = pszSubjectNew; CHECKHR(hr = pRootProps->SetProp(PIDTOSTR(PID_HDR_SUBJECT), 0, &rVariant)); // Save Root Header CHECKHR(hr = pRootProps->Save(pstmPart, TRUE)); // Emit Line Break CHECKHR(hr = pstmPart->Write(c_szCRLF, lstrlen(c_szCRLF), NULL)); // Copy bytes from lpstmMsg to pstmPart CHECKHR(hr = HrCopyStreamCBEndOnCRLF(pstmMsg, pstmPart, cbMaxPart - cbHeader, &cbActual)); // Increment read cbRead += cbActual; // If cbActual is less than cbMaxMsgSize-cbHeader, better be the last part #ifdef DEBUG if (iPart + 1 < cParts && cbActual < (cbMaxPart - cbHeader)) AssertSz (FALSE, "One more partial message is going to be produced than needed. This should be harmless."); #endif // Commit pstmPart CHECKHR(hr = pstmPart->Commit(STGC_DEFAULT)); // Rewind it CHECKHR(hr = HrRewindStream(pstmPart)); // Create Message Part... CHECKHR(hr = MimeOleCreateMessage(NULL, &pmsgPart)); // Make the message build itself CHECKHR (hr = pmsgPart->Load(pstmPart)); // We need another message and stream CHECKHR (hr = pParts->AddPart(pmsgPart)); // Cleanup SafeRelease(pmsgPart); SafeRelease(pstmPart); } // Lets hope we read everything... AssertSz(cbRead == cbMessage, "Please let sbailey know if these fails."); exit: // Succeeded if (SUCCEEDED(hr)) { // Returns Parts Object (*ppParts) = pParts; (*ppParts)->AddRef(); } // Cleanup SafeRelease(pRootBody); SafeRelease(pstmMsg); SafeRelease(pParts); SafeRelease(pRootProps); SafeRelease(pmsgPart); SafeRelease(pstmPart); SafeMemFree(pszSubjectAddOn); SafeMemFree(pszSubjectNew); SafeMemFree(prghAttach); MimeOleVariantFree(&rSubject); MimeOleVariantFree(&rFileName); // Done return hr; } // -------------------------------------------------------------------------------- // CompareBlob // -------------------------------------------------------------------------------- int CompareBlob(LPCBLOB pBlob1, LPCBLOB pBlob2) { // Locals register int ret = 0; Assert(pBlob1 && pBlob2); if (pBlob1->cbSize != pBlob2->cbSize) ret = pBlob1->cbSize - pBlob2->cbSize; else ret = memcmp(pBlob1->pBlobData, pBlob2->pBlobData, pBlob2->cbSize); return ret; } // -------------------------------------------------------------------------------- // HrCopyBlob // -------------------------------------------------------------------------------- HRESULT HrCopyBlob(LPCBLOB pIn, LPBLOB pOut) { // Locals HRESULT hr; ULONG cb = 0; Assert(pIn && pOut); if (pIn->cbSize == 0) { pOut->cbSize = 0; pOut->pBlobData = NULL; return S_OK; } // Dup It... cb = pIn->cbSize; #ifdef _WIN64 cb = LcbAlignLcb(cb); #endif //_WIN64 if (SUCCEEDED(hr = HrAlloc((LPVOID *)&pOut->pBlobData, cb))) { // Copy Memory CopyMemory(pOut->pBlobData, pIn->pBlobData, pIn->cbSize); // Set Size pOut->cbSize = pIn->cbSize; } else { pOut->cbSize = 0; } // Done return hr; } // -------------------------------------------------------------------------------- // PriorityFromStringA // -------------------------------------------------------------------------------- IMSGPRIORITY PriorityFromStringA(LPCSTR pszPriority) { // Locals IMSGPRIORITY priority=IMSG_PRI_NORMAL; DWORD dwPriority; // If IsDigit... if (IsDigit((LPSTR)pszPriority)) { // Convert dwPriority = (DWORD)StrToInt(pszPriority); // Map to pri type if (dwPriority <= 2) priority = IMSG_PRI_HIGH; else if (dwPriority > 3) priority = IMSG_PRI_LOW; } // Otheriwse, map from high, normal and low... else { // High, Highest, Low, Lowest if (lstrcmpi(pszPriority, STR_PRI_MS_HIGH) == 0) priority = IMSG_PRI_HIGH; else if (lstrcmpi(pszPriority, STR_PRI_MS_LOW) == 0) priority = IMSG_PRI_LOW; else if (lstrcmpi(pszPriority, STR_PRI_HIGHEST) == 0) priority = IMSG_PRI_HIGH; else if (lstrcmpi(pszPriority, STR_PRI_LOWEST) == 0) priority = IMSG_PRI_LOW; } // Done return priority; } // -------------------------------------------------------------------------------- // PriorityFromStringW // -------------------------------------------------------------------------------- IMSGPRIORITY PriorityFromStringW(LPCWSTR pwszPriority) { // Locals HRESULT hr=S_OK; LPSTR pszPriority=NULL; IMSGPRIORITY priority=IMSG_PRI_NORMAL; // Convert to ANSI CHECKALLOC(pszPriority = PszToANSI(CP_ACP, pwszPriority)); // Normal Conversion priority = PriorityFromStringA(pszPriority); exit: // Done return priority; } // -------------------------------------------------------------------------------- // MimeOleCompareUrlSimple // -------------------------------------------------------------------------------- HRESULT MimeOleCompareUrlSimple(LPCSTR pszUrl1, LPCSTR pszUrl2) { // Locals HRESULT hr=S_OK; CHAR chUrl1; CHAR chUrl2; // Skip leading white space while(*pszUrl1 && (' ' == *pszUrl1 || '\t' == *pszUrl1)) pszUrl1++; while(*pszUrl2 && (' ' == *pszUrl2 || '\t' == *pszUrl2)) pszUrl2++; // Start the loop while(*pszUrl1 && *pszUrl2) { // Case Insensitive chUrl1 = TOUPPERA(*pszUrl1); chUrl2 = TOUPPERA(*pszUrl2); // Not Equal if (chUrl1 != chUrl2) { hr = S_FALSE; break; } // Next pszUrl1++; pszUrl2++; } // Skip over trailing whitespace while(*pszUrl1 && (' ' == *pszUrl1 || '\t' == *pszUrl1)) pszUrl1++; while(*pszUrl2 && (' ' == *pszUrl2 || '\t' == *pszUrl2)) pszUrl2++; // No substrings if ('\0' != *pszUrl1 || '\0' != *pszUrl2) hr = S_FALSE; // Done return hr; } // -------------------------------------------------------------------------------- // MimeOleCompareUrl // -------------------------------------------------------------------------------- HRESULT MimeOleCompareUrl(LPCSTR pszCurrentUrl, BOOL fUnEscapeCurrent, LPCSTR pszCompareUrl, BOOL fUnEscapeCompare) { // Locals HRESULT hr=S_OK; LPSTR pszUrl1=(LPSTR)pszCurrentUrl; LPSTR pszUrl2=(LPSTR)pszCompareUrl; CHAR chPrev='\0'; CHAR chUrl1; CHAR chUrl2; ULONG cb; // Stack Strings STACKSTRING_DEFINE(rCurrentUrl, 255); STACKSTRING_DEFINE(rCompareUrl, 255); // fUnEscapeCurrent if (fUnEscapeCurrent) { // Get Size cb = lstrlen(pszCurrentUrl) + 1; // Set Size STACKSTRING_SETSIZE(rCurrentUrl, cb); // Copy CopyMemory(rCurrentUrl.pszVal, pszCurrentUrl, cb); // Dupe It CHECKHR(hr = UrlUnescapeA(rCurrentUrl.pszVal, NULL, NULL, URL_UNESCAPE_INPLACE)); // Adjust pszUrl1 pszUrl1 = rCurrentUrl.pszVal; } // fUnEscapeCurrent if (fUnEscapeCompare) { // Get Size cb = lstrlen(pszCompareUrl) + 1; // Set Size STACKSTRING_SETSIZE(rCompareUrl, cb); // Copy CopyMemory(rCompareUrl.pszVal, pszCompareUrl, cb); // Dupe It CHECKHR(hr = UrlUnescapeA(rCompareUrl.pszVal, NULL, NULL, URL_UNESCAPE_INPLACE)); // Adjust pszUrl2 pszUrl2 = rCompareUrl.pszVal; } // Skip leading white space while(*pszUrl1 && (' ' == *pszUrl1 || '\t' == *pszUrl1)) pszUrl1++; while(*pszUrl2 && (' ' == *pszUrl2 || '\t' == *pszUrl2)) pszUrl2++; // Start the loop while(*pszUrl1 && *pszUrl2) { // Case Insensitive chUrl1 = TOUPPERA(*pszUrl1); chUrl2 = TOUPPERA(*pszUrl2); // Special case search for '/' if (':' == chPrev && '/' == chUrl2 && '/' != *(pszUrl2 + 1) && '/' == chUrl1 && '/' == *(pszUrl1 + 1)) { // Next pszUrl1++; // Done if ('\0' == *pszUrl1) { hr = S_FALSE; break; } // Rset chUrl1 chUrl1 = TOUPPERA(*pszUrl1); } // Not Equal if (chUrl1 != chUrl2) { hr = S_FALSE; break; } // Save Prev chPrev = *pszUrl1; // Next pszUrl1++; pszUrl2++; } // Skip over trailing whitespace while(*pszUrl1 && (' ' == *pszUrl1 || '\t' == *pszUrl1)) pszUrl1++; while(*pszUrl2 && (' ' == *pszUrl2 || '\t' == *pszUrl2)) pszUrl2++; // Raid 63823: Mail : Content-Location Href's inside the message do not work if there is a Start Parameter in headers // Skim over remaining '/' in both urls while (*pszUrl1 && '/' == *pszUrl1) pszUrl1++; while (*pszUrl2 && '/' == *pszUrl2) pszUrl2++; // No substrings if ('\0' != *pszUrl1 || '\0' != *pszUrl2) hr = S_FALSE; // file://d:\test\foo.mhtml == d:\test\foo.mhtml if (S_FALSE == hr && StrCmpNI(pszCurrentUrl, "file:", 5) == 0) { // Skip over file: LPSTR pszRetryUrl = (LPSTR)(pszCurrentUrl + 5); // Skip over forward slashes while(*pszRetryUrl && '/' == *pszRetryUrl) pszRetryUrl++; // Compare Again hr = MimeOleCompareUrl(pszRetryUrl, fUnEscapeCurrent, pszCompareUrl, fUnEscapeCompare); } exit: // Cleanup STACKSTRING_FREE(rCurrentUrl); STACKSTRING_FREE(rCompareUrl); // Done return hr; } // -------------------------------------------------------------------------------- // MimeOleWrapHeaderText // -------------------------------------------------------------------------------- HRESULT MimeOleWrapHeaderText(CODEPAGEID codepage, ULONG cchMaxLine, LPCSTR pszLine, ULONG cchLine, LPSTREAM pStream) { // Locals HRESULT hr=S_OK; ULONG cchIndex=0; ULONG cchWrite; // Invalid Arg Assert(pszLine && pszLine[cchLine] == '\0' && pStream && cchMaxLine >= 2); // Start Writing while(1) { // Validate Assert(cchIndex <= cchLine); // Compute cchWrite cchWrite = min(cchLine - cchIndex, cchMaxLine - 2); // Done if (0 == cchWrite) { // Final Line Wrap CHECKHR(hr = pStream->Write(c_szCRLF, 2, NULL)); // Done break; } // Write the line CHECKHR(hr = pStream->Write(pszLine + cchIndex, cchWrite, NULL)); // If there is still more text if (cchIndex + cchWrite < cchLine) { // Write '\r\n\t' CHECKHR(hr = pStream->Write(c_szCRLFTab, 3, NULL)); } // Increment iText cchIndex += cchWrite; } exit: // Done return hr; } // -------------------------------------------------------------------------------- // MimeOleCreateBody // -------------------------------------------------------------------------------- HRESULT MimeOleCreateBody(IMimeBody **ppBody) { HRESULT hr; CMessageBody *pNew; pNew = new CMessageBody(NULL, NULL); if (NULL == pNew) return TrapError(E_OUTOFMEMORY); hr = pNew->QueryInterface(IID_IMimeBody, (LPVOID *)ppBody); pNew->Release(); return hr; } // -------------------------------------------------------------------------------- // MimeOleGetSentTime // -------------------------------------------------------------------------------- HRESULT MimeOleGetSentTime(LPCONTAINER pContainer, DWORD dwFlags, LPMIMEVARIANT pValue) { // Locals HRESULT hr=S_OK; // Get the data: header field if (FAILED(pContainer->GetProp(SYM_HDR_DATE, dwFlags, pValue))) { // Locals SYSTEMTIME st; MIMEVARIANT rValue; // Setup rValue rValue.type = MVT_VARIANT; rValue.rVariant.vt = VT_FILETIME; // Get current systemtime GetSystemTime(&st); SystemTimeToFileTime(&st, &rValue.rVariant.filetime); // If the Conversion Fails, get the current time CHECKHR(hr = pContainer->HrConvertVariant(SYM_ATT_SENTTIME, NULL, IET_DECODED, dwFlags, 0, &rValue, pValue)); } exit: // Done return hr; }