You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
737 lines
20 KiB
737 lines
20 KiB
|
|
/*
|
|
* m h t m l . c p p
|
|
*
|
|
* Purpose:
|
|
* MHTML packing utilities
|
|
*
|
|
* History
|
|
* August '96: brettm - created
|
|
*
|
|
* Copyright (C) Microsoft Corp. 1995, 1996.
|
|
*/
|
|
#include <pch.hxx>
|
|
#include "dllmain.h"
|
|
#include "resource.h"
|
|
#include "strconst.h"
|
|
#include "htmlstr.h"
|
|
#include "mimeutil.h"
|
|
#include "triutil.h"
|
|
#include "util.h"
|
|
#include "oleutil.h"
|
|
#include "demand.h"
|
|
#include "mhtml.h"
|
|
#include "tags.h"
|
|
|
|
ASSERTDATA
|
|
|
|
/*
|
|
* m a c r o s
|
|
*/
|
|
|
|
/*
|
|
* c o n s t a n t s
|
|
*/
|
|
|
|
static const TCHAR c_szRegExtension[] = "SOFTWARE\\Microsoft\\MimeEdit\\MHTML Extension";
|
|
|
|
|
|
|
|
/*
|
|
* t y p e d e f s
|
|
*/
|
|
|
|
/*
|
|
* g l o b a l s
|
|
*/
|
|
|
|
/*
|
|
* f u n c t i o n p r o t y p e s
|
|
*/
|
|
|
|
|
|
/*
|
|
* f u n c t i o n s
|
|
*/
|
|
|
|
|
|
class CPackager
|
|
{
|
|
public:
|
|
|
|
CPackager();
|
|
virtual ~CPackager();
|
|
|
|
ULONG AddRef();
|
|
ULONG Release();
|
|
|
|
HRESULT PackageData(IHTMLDocument2 *pDoc, IMimeMessage *pMsgSrc, IMimeMessage *pMsgDest, DWORD dwFlags, IHashTable *pHashRestricted);
|
|
|
|
private:
|
|
ULONG m_cRef;
|
|
IMimeMessage *m_pMsgSrc,
|
|
*m_pMsgDest;
|
|
IHashTable *m_pHash,
|
|
*m_pHashRestricted;
|
|
|
|
HRESULT _PackageCollectionData(IMimeEditTagCollection *pCollect);
|
|
HRESULT _PackageUrlData(IMimeEditTag *pTag);
|
|
|
|
HRESULT _RemapUrls(IMimeEditTagCollection *pCollect, BOOL fSave);
|
|
HRESULT _CanonicaliseContentId(LPWSTR pszUrlW, BSTR *pbstr);
|
|
HRESULT _ShouldUseContentId(LPSTR pszUrl);
|
|
HRESULT _BuildCollectionTable(DWORD dwFlags, IHTMLDocument2 *pDoc, IMimeEditTagCollection ***prgpCollect, ULONG *pcCount);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
CPackager::CPackager()
|
|
{
|
|
m_cRef = 1;
|
|
m_pMsgSrc = NULL;
|
|
m_pMsgDest = NULL;
|
|
m_pHash = NULL;
|
|
m_pHashRestricted = NULL;
|
|
}
|
|
|
|
CPackager::~CPackager()
|
|
{
|
|
ReleaseObj(m_pMsgSrc);
|
|
ReleaseObj(m_pMsgDest);
|
|
ReleaseObj(m_pHash);
|
|
ReleaseObj(m_pHashRestricted);
|
|
}
|
|
|
|
|
|
ULONG CPackager::AddRef()
|
|
{
|
|
return ++m_cRef;
|
|
}
|
|
|
|
ULONG CPackager::Release()
|
|
{
|
|
if (--m_cRef==0)
|
|
{
|
|
delete this;
|
|
return 0;
|
|
}
|
|
return m_cRef;
|
|
}
|
|
|
|
HRESULT CPackager::PackageData(IHTMLDocument2 *pDoc, IMimeMessage *pMsgSrc, IMimeMessage *pMsgDest, DWORD dwFlags, IHashTable *pHashRestricted)
|
|
{
|
|
LPSTREAM pstm;
|
|
HRESULT hr,
|
|
hrWarnings=S_OK;
|
|
HBODY hBodyHtml=0;
|
|
IMimeEditTagCollection **rgpCollect=NULL;
|
|
ULONG uCollect,
|
|
cCollect=0,
|
|
cItems=0,
|
|
cCount;
|
|
|
|
// BUGBUG: propagate hrWarnings back up
|
|
TraceCall("CBody::Save");
|
|
|
|
if (pDoc==NULL || pMsgDest==NULL)
|
|
return E_INVALIDARG;
|
|
|
|
ReplaceInterface(m_pMsgSrc, pMsgSrc);
|
|
ReplaceInterface(m_pMsgDest, pMsgDest);
|
|
ReplaceInterface(m_pHashRestricted, pHashRestricted);
|
|
|
|
hr = _BuildCollectionTable(dwFlags, pDoc, &rgpCollect, &cCollect);
|
|
if (FAILED(hr))
|
|
hrWarnings = hr;
|
|
|
|
// count the number of items we need to package and
|
|
// prepare a hash-table for duplicate entries
|
|
for (uCollect = 0; uCollect < cCollect; uCollect++)
|
|
{
|
|
Assert (rgpCollect[uCollect]);
|
|
|
|
if ((rgpCollect[uCollect])->Count(&cCount)==S_OK)
|
|
cItems+=cCount;
|
|
}
|
|
|
|
if (cItems)
|
|
{
|
|
// create the hashtable
|
|
hr = MimeOleCreateHashTable(cItems, TRUE, &m_pHash);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
}
|
|
|
|
// package the data required for each collection
|
|
for (uCollect = 0; uCollect < cCollect; uCollect++)
|
|
{
|
|
// package the data
|
|
hr = _PackageCollectionData(rgpCollect[uCollect]);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
if (hr != S_OK) // retain any 'warnings'
|
|
hrWarnings = hr;
|
|
|
|
// map all the URLs to CID:// urls if necessary
|
|
hr = _RemapUrls(rgpCollect[uCollect], TRUE);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
}
|
|
|
|
// get an HTML stream
|
|
if(dwFlags & MECD_HTML)
|
|
{
|
|
hr = GetBodyStream(pDoc, TRUE, &pstm);
|
|
if (!FAILED(hr))
|
|
{
|
|
hr = pMsgDest->SetTextBody(TXT_HTML, IET_INETCSET, NULL, pstm, &hBodyHtml);
|
|
pstm->Release();
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
goto error;
|
|
}
|
|
|
|
// get a plain-text stream
|
|
if(dwFlags & MECD_PLAINTEXT)
|
|
{
|
|
hr = GetBodyStream(pDoc, FALSE, &pstm);
|
|
if (!FAILED(hr))
|
|
{
|
|
// if we set a html body part, then be sure to pass in hBodyHtml so Opie knows what the alternate is
|
|
// alternative to.
|
|
hr = pMsgDest->SetTextBody(TXT_PLAIN, IET_UNICODE, hBodyHtml, pstm, NULL);
|
|
pstm->Release();
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
goto error;
|
|
}
|
|
|
|
|
|
for (uCollect = 0; uCollect < cCollect; uCollect++)
|
|
{
|
|
// remap all of the URL's back to their original location
|
|
hr = _RemapUrls(rgpCollect[uCollect], FALSE);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
error:
|
|
// release the collection objects
|
|
if (rgpCollect)
|
|
{
|
|
for (uCollect = 0; uCollect < cCollect; uCollect++)
|
|
ReleaseObj(rgpCollect[uCollect]);
|
|
MemFree(rgpCollect);
|
|
}
|
|
|
|
return hr==S_OK ? hrWarnings : hr;
|
|
}
|
|
|
|
|
|
HRESULT CPackager::_BuildCollectionTable(DWORD dwFlags, IHTMLDocument2 *pDoc, IMimeEditTagCollection ***prgpCollect, ULONG *pcCount)
|
|
{
|
|
IMimeEditTagCollection **rgpCollect=NULL;
|
|
HKEY hkey;
|
|
ULONG cPlugin=0,
|
|
cCount = 0,
|
|
cAlloc = 0,
|
|
i,
|
|
cb;
|
|
TCHAR szGUID[MAX_PATH];
|
|
IID iid;
|
|
HRESULT hr=E_FAIL;
|
|
LONG lResult;
|
|
LPWSTR pszGuidW;
|
|
|
|
*prgpCollect = NULL;
|
|
*pcCount = NULL;
|
|
|
|
// reserve space for 2 image collections (bgimage and img)
|
|
if (dwFlags & MECD_ENCODEIMAGES)
|
|
cAlloc+=2;
|
|
|
|
// reserver space for bgsounds
|
|
if (dwFlags & MECD_ENCODESOUNDS)
|
|
cAlloc++;
|
|
|
|
// reserver space for active-movies
|
|
if (dwFlags & MECD_ENCODEVIDEO)
|
|
cAlloc++;
|
|
|
|
// reserve space for plugin types
|
|
if ((dwFlags & MECD_ENCODEPLUGINS) &&
|
|
RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegExtension, 0, KEY_READ, &hkey) == ERROR_SUCCESS)
|
|
{
|
|
if (RegQueryInfoKey(hkey, NULL, NULL, 0, &cPlugin, NULL, NULL, NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS &&
|
|
cPlugin > 0)
|
|
cAlloc += cPlugin;
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
// allocate the table of collection pointers
|
|
if (!MemAlloc((LPVOID *)&rgpCollect, sizeof(IMimeEditTagCollection *) * cAlloc))
|
|
{
|
|
hr = TraceResult(E_OUTOFMEMORY);
|
|
goto error;
|
|
}
|
|
|
|
// zero-init the table
|
|
ZeroMemory((LPVOID)rgpCollect, sizeof(IMimeEditTagCollection *) * cAlloc);
|
|
|
|
|
|
if (dwFlags & MECD_ENCODEIMAGES)
|
|
{
|
|
// image collection
|
|
if (FAILED(CreateOEImageCollection(pDoc, &rgpCollect[cCount])))
|
|
hr = MIMEEDIT_W_BADURLSNOTATTACHED; // bubble back a warning, but don't fail
|
|
else
|
|
cCount++;
|
|
}
|
|
|
|
if (dwFlags & MECD_ENCODEIMAGES)
|
|
{
|
|
// background images
|
|
if (FAILED(CreateBGImageCollection(pDoc, &rgpCollect[cCount])))
|
|
hr = MIMEEDIT_W_BADURLSNOTATTACHED; // bubble back a warning, but don't fail
|
|
else
|
|
cCount++;
|
|
}
|
|
|
|
if (dwFlags & MECD_ENCODESOUNDS)
|
|
{
|
|
// background sounds
|
|
if (FAILED(CreateBGSoundCollection(pDoc, &rgpCollect[cCount])))
|
|
hr = MIMEEDIT_W_BADURLSNOTATTACHED; // bubble back a warning, but don't fail
|
|
else
|
|
cCount++;
|
|
}
|
|
|
|
|
|
if (dwFlags & MECD_ENCODEVIDEO)
|
|
{
|
|
// active-movie controls (for MSPHONE)
|
|
if (FAILED(CreateActiveMovieCollection(pDoc, &rgpCollect[cCount])))
|
|
hr = MIMEEDIT_W_BADURLSNOTATTACHED; // bubble back a warning, but don't fail
|
|
else
|
|
cCount++;
|
|
}
|
|
|
|
if ((dwFlags & MECD_ENCODEPLUGINS) &&
|
|
cPlugin &&
|
|
RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegExtension, 0, KEY_READ, &hkey) == ERROR_SUCCESS)
|
|
{
|
|
// Start Enumerating the keys
|
|
for (i = 0; i < cPlugin; i++)
|
|
{
|
|
// Enumerate Friendly Names
|
|
cb = sizeof(szGUID);
|
|
lResult = RegEnumKeyEx(hkey, i, szGUID, &cb, 0, NULL, NULL, NULL);
|
|
|
|
// No more items
|
|
if (lResult == ERROR_NO_MORE_ITEMS)
|
|
break;
|
|
|
|
// Error, lets move onto the next account
|
|
if (lResult != ERROR_SUCCESS)
|
|
{
|
|
Assert(FALSE);
|
|
continue;
|
|
}
|
|
|
|
pszGuidW = PszToUnicode(CP_ACP, szGUID);
|
|
if (pszGuidW)
|
|
{
|
|
// convert the string to a guid
|
|
if (IIDFromString(pszGuidW, &iid) == S_OK)
|
|
{
|
|
// cocreate the plugin
|
|
if (CoCreateInstance(iid, NULL, CLSCTX_INPROC_SERVER, IID_IMimeEditTagCollection, (LPVOID *)&rgpCollect[cCount])==S_OK)
|
|
{
|
|
// try and init the document
|
|
if (!FAILED((rgpCollect[cCount])->Init(pDoc)))
|
|
{
|
|
cCount++;
|
|
}
|
|
else
|
|
{
|
|
SafeRelease(rgpCollect[cCount]);
|
|
}
|
|
}
|
|
else
|
|
hr = MIMEEDIT_W_BADURLSNOTATTACHED; // bubble back a warning, but don't fail
|
|
}
|
|
MemFree(pszGuidW);
|
|
}
|
|
}
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
|
|
*prgpCollect = rgpCollect;
|
|
*pcCount = cCount;
|
|
rgpCollect = NULL;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (rgpCollect)
|
|
{
|
|
for (i = 0; i < cAlloc; i++)
|
|
SafeRelease(rgpCollect[i]);
|
|
|
|
MemFree(rgpCollect);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CPackager::_PackageCollectionData(IMimeEditTagCollection *pCollect)
|
|
{
|
|
ULONG cFetched;
|
|
IMimeEditTag *pTag;
|
|
BOOL fBadLinks = FALSE;
|
|
|
|
Assert (pCollect);
|
|
|
|
pCollect->Reset();
|
|
|
|
while (pCollect->Next(1, &pTag, &cFetched)==S_OK && cFetched==1)
|
|
{
|
|
Assert (pTag);
|
|
|
|
if (pTag->CanPackage() != S_OK ||
|
|
_PackageUrlData(pTag) != S_OK)
|
|
{
|
|
// we failed to package this body part. Be sure to return a warning when we're done
|
|
// but let's keep trucking for now...
|
|
fBadLinks = TRUE;
|
|
}
|
|
pTag->Release();
|
|
}
|
|
|
|
return fBadLinks ? MIMEEDIT_W_BADURLSNOTATTACHED : S_OK;;
|
|
}
|
|
|
|
|
|
HRESULT CPackager::_PackageUrlData(IMimeEditTag *pTag)
|
|
{
|
|
HRESULT hr=S_OK;
|
|
LPSTREAM pstm;
|
|
HBODY hBody=0,
|
|
hBodyOld;
|
|
LPSTR lpszCID=0,
|
|
lpszCIDUrl;
|
|
LPSTR pszUrlA=0,
|
|
pszBody;
|
|
|
|
BSTR bstrSrc=NULL,
|
|
bstrCID=NULL;
|
|
LPWSTR pszMimeTypeW=NULL;
|
|
|
|
if (pTag == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
pTag->GetSrc(&bstrSrc);
|
|
|
|
pszUrlA = PszToANSI(CP_ACP, bstrSrc);
|
|
if (!pszUrlA)
|
|
return TraceResult(E_OUTOFMEMORY);
|
|
|
|
DWORD cchSize = (lstrlenA(pszUrlA) + 1);
|
|
// if the URL is a restricted URL then we simply exit without packing any data
|
|
if (m_pHashRestricted &&
|
|
m_pHashRestricted->Find(pszUrlA, FALSE, (LPVOID *)&hBody)==S_OK)
|
|
{
|
|
MemFree(pszUrlA);
|
|
return S_OK;
|
|
}
|
|
|
|
// hack: if it's an MHTML: url then we have to fixup to get the cid:
|
|
if (StrCmpNIA(pszUrlA, "mhtml:", 6)==0)
|
|
{
|
|
if (!FAILED(MimeOleParseMhtmlUrl(pszUrlA, NULL, &pszBody)))
|
|
{
|
|
// pszBody pszUrlA is guarnteed to be smaller
|
|
StrCpyNA(pszUrlA, pszBody, cchSize * sizeof(pszUrlA[0]));
|
|
SafeMimeOleFree(pszBody);
|
|
}
|
|
}
|
|
|
|
if (m_pHash &&
|
|
m_pHash->Find(pszUrlA, FALSE, (LPVOID *)&hBody)==S_OK)
|
|
{
|
|
// we've already seen this url one before in this document, and have it's HBODY already
|
|
// so there's no need to do any work
|
|
// try and get the content-id incase the caller is interested
|
|
|
|
// BUGBUG? possible more than CID need to be ported here...
|
|
MimeOleGetBodyPropA(m_pMsgDest, hBody, PIDTOSTR(PID_HDR_CNTID), NOFLAGS, &lpszCID);
|
|
goto found;
|
|
}
|
|
|
|
// see if szUrl is in the related section of the source message
|
|
if (m_pMsgSrc &&
|
|
m_pMsgSrc->ResolveURL(NULL, NULL, pszUrlA, 0, &hBody)==S_OK)
|
|
{
|
|
hBodyOld = hBody;
|
|
|
|
// this URL is already in the related section, and we haven't seen it already.
|
|
// then let's bind to the data and attach it
|
|
if (m_pMsgSrc->BindToObject(hBody, IID_IStream, (LPVOID *)&pstm)==S_OK)
|
|
{
|
|
// if it's a FILE:// url we use CID: else we use Content-Location
|
|
hr = m_pMsgDest->AttachURL(NULL, pszUrlA, (_ShouldUseContentId(pszUrlA)==S_OK ? URL_ATTACH_GENERATE_CID : 0 )|URL_ATTACH_SET_CNTTYPE, pstm, &lpszCID, &hBody);
|
|
pstm->Release();
|
|
}
|
|
|
|
// be sure to copy the old content-type and filename over
|
|
HrCopyHeader(m_pMsgDest, hBody, m_pMsgSrc, hBodyOld, PIDTOSTR(PID_HDR_CNTTYPE));
|
|
HrCopyHeader(m_pMsgDest, hBody, m_pMsgSrc, hBodyOld, PIDTOSTR(PID_HDR_CNTLOC));
|
|
HrCopyHeader(m_pMsgDest, hBody, m_pMsgSrc, hBodyOld, PIDTOSTR(STR_PAR_FILENAME));
|
|
}
|
|
else
|
|
{
|
|
// if not, then let's try and bind to it ourselves. We don't go thro' MimeOle for this, as we want to
|
|
// fail if the URL is bad, so we don't add the part to the Tree.
|
|
hr = HrBindToUrl(pszUrlA, &pstm);
|
|
if (!FAILED(hr))
|
|
{
|
|
hr = SniffStreamForMimeType(pstm, &pszMimeTypeW);
|
|
if (!FAILED(hr))
|
|
{
|
|
if (pTag->IsValidMimeType(pszMimeTypeW)==S_OK)
|
|
{
|
|
LPWSTR pszFileNameW;
|
|
|
|
// if it's a FILE:// url we use CID: else we use Content-Location
|
|
hr = m_pMsgDest->AttachURL(NULL, pszUrlA, (_ShouldUseContentId(pszUrlA)==S_OK ? URL_ATTACH_GENERATE_CID : 0 )|URL_ATTACH_SET_CNTTYPE, pstm, &lpszCID, &hBody);
|
|
if (!FAILED(hr))
|
|
{
|
|
// if attaching a new attachment, try and sniff the file-name
|
|
pszFileNameW = PathFindFileNameW(bstrSrc);
|
|
if (pszFileNameW)
|
|
MimeOleSetBodyPropW(m_pMsgDest, hBody, PIDTOSTR(STR_PAR_FILENAME), NOFLAGS, pszFileNameW);
|
|
}
|
|
}
|
|
else
|
|
hr = E_FAIL;
|
|
|
|
CoTaskMemFree(pszMimeTypeW);
|
|
}
|
|
pstm->Release();
|
|
}
|
|
}
|
|
|
|
// add to the hash table
|
|
if (m_pHash &&
|
|
!FAILED(hr) && hBody)
|
|
hr = m_pHash->Insert(pszUrlA, (void*)hBody, NOFLAGS);
|
|
|
|
|
|
found:
|
|
// if we found the content-ID we need to return an allocated BSTR with it in.
|
|
if (lpszCID)
|
|
{
|
|
LPWSTR pszCIDW;
|
|
|
|
pszCIDW = PszToUnicode(CP_ACP, lpszCID);
|
|
if (pszCIDW)
|
|
{
|
|
if (_CanonicaliseContentId(pszCIDW, &bstrCID)==S_OK)
|
|
{
|
|
pTag->SetDest(bstrCID);
|
|
SysFreeString(bstrCID);
|
|
}
|
|
MemFree(pszCIDW);
|
|
}
|
|
SafeMimeOleFree(lpszCID);
|
|
}
|
|
|
|
SafeMemFree(pszUrlA);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CPackager::_ShouldUseContentId(LPSTR pszUrl)
|
|
{
|
|
// we use Content-Location for urls that begin with "http:", "https:" and "ftp:" for all
|
|
// others we will use Content-Id
|
|
|
|
if (StrCmpNIA(pszUrl, "ftp:", 4)==0 ||
|
|
StrCmpNIA(pszUrl, "http:", 5)==0 ||
|
|
StrCmpNIA(pszUrl, "https:", 6)==0)
|
|
return S_FALSE;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
HRESULT CPackager::_RemapUrls(IMimeEditTagCollection *pCollect, BOOL fSave)
|
|
{
|
|
ULONG cFetched;
|
|
IMimeEditTag *pTag;
|
|
|
|
Assert (pCollect);
|
|
|
|
pCollect->Reset();
|
|
|
|
while (pCollect->Next(1, &pTag, &cFetched)==S_OK && cFetched==1)
|
|
{
|
|
Assert (pTag);
|
|
|
|
if (fSave)
|
|
pTag->OnPreSave();
|
|
else
|
|
pTag->OnPostSave();
|
|
|
|
pTag->Release();
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CPackager::_CanonicaliseContentId(LPWSTR pszUrlW, BSTR *pbstr)
|
|
{
|
|
HRESULT hr;
|
|
|
|
*pbstr = NULL;
|
|
|
|
if (StrCmpNIW(pszUrlW, L"cid:", 4)!=0)
|
|
{
|
|
DWORD cchSize = (lstrlenW(pszUrlW) + 4);
|
|
*pbstr = SysAllocStringLen(NULL, cchSize);
|
|
if (*pbstr)
|
|
{
|
|
StrCpyNW(*pbstr, L"cid:", cchSize);
|
|
StrCatBuffW(*pbstr, pszUrlW, cchSize);
|
|
}
|
|
}
|
|
else
|
|
*pbstr = SysAllocString(pszUrlW);
|
|
|
|
return *pbstr ? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
|
|
HRESULT SaveAsMHTML(IHTMLDocument2 *pDoc, DWORD dwFlags, IMimeMessage *pMsgSrc, IMimeMessage *pMsgDest, IHashTable *pHashRestricted)
|
|
{
|
|
CPackager *pPacker=0;
|
|
HRESULT hr;
|
|
|
|
TraceCall("CBody::Save");
|
|
|
|
pPacker = new CPackager();
|
|
if (!pPacker)
|
|
{
|
|
hr = TraceResult(E_OUTOFMEMORY);
|
|
goto error;
|
|
}
|
|
|
|
hr = pPacker->PackageData(pDoc, pMsgSrc, pMsgDest, dwFlags, pHashRestricted);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
error:
|
|
ReleaseObj(pPacker);
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
HRESULT HashExternalReferences(IHTMLDocument2 *pDoc, IMimeMessage *pMsg, IHashTable **ppHash)
|
|
{
|
|
HRESULT hr;
|
|
IMimeEditTagCollection *rgpCollect[4];
|
|
IMimeEditTagCollection *pCollect;
|
|
ULONG uCollect,
|
|
cCollect=0,
|
|
cItems=0,
|
|
cCount,
|
|
cFetched;
|
|
IHashTable *pHash;
|
|
IMimeEditTag *pTag;
|
|
BSTR bstrSrc;
|
|
LPSTR pszUrlA;
|
|
|
|
// keep trucking if we fail, to catch as many as we can
|
|
*ppHash = NULL;
|
|
|
|
// image collection
|
|
if (CreateOEImageCollection(pDoc, &rgpCollect[cCollect])==S_OK)
|
|
cCollect++;
|
|
|
|
// background images
|
|
if (CreateBGImageCollection(pDoc, &rgpCollect[cCollect])==S_OK)
|
|
cCollect++;
|
|
|
|
// background sounds
|
|
if (CreateBGSoundCollection(pDoc, &rgpCollect[cCollect])==S_OK)
|
|
cCollect++;
|
|
|
|
// active-movie controls (for MSPHONE)
|
|
if (CreateActiveMovieCollection(pDoc, &rgpCollect[cCollect])==S_OK)
|
|
cCollect++;
|
|
|
|
// count the number of items we need to package and
|
|
// prepare a hash-table for duplicate entries
|
|
for (uCollect = 0; uCollect < cCollect; uCollect++)
|
|
{
|
|
Assert (rgpCollect[uCollect]);
|
|
|
|
if ((rgpCollect[uCollect])->Count(&cCount)==S_OK)
|
|
cItems+=cCount;
|
|
}
|
|
|
|
// create the hashtable
|
|
hr = MimeOleCreateHashTable(cItems, TRUE, &pHash);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
// looks for external references in each
|
|
for (uCollect = 0; uCollect < cCollect; uCollect++)
|
|
{
|
|
pCollect = rgpCollect[uCollect];
|
|
if (pCollect)
|
|
{
|
|
pCollect->Reset();
|
|
|
|
while (pCollect->Next(1, &pTag, &cFetched)==S_OK && cFetched==1)
|
|
{
|
|
Assert (pTag);
|
|
|
|
if (pTag->GetSrc(&bstrSrc)==S_OK)
|
|
{
|
|
pszUrlA = PszToANSI(CP_ACP, bstrSrc);
|
|
if (pszUrlA)
|
|
{
|
|
if (HrFindUrlInMsg(pMsg, pszUrlA, FINDURL_SEARCH_RELATED_ONLY, NULL)!=S_OK)
|
|
{
|
|
// this URL was not in the message and it external
|
|
// let's track it as a restricted URL in our hash
|
|
pHash->Insert(pszUrlA, NULL, NOFLAGS);
|
|
}
|
|
MemFree(pszUrlA);
|
|
}
|
|
SysFreeString(bstrSrc);
|
|
}
|
|
pTag->Release();
|
|
}
|
|
pCollect->Release();
|
|
}
|
|
}
|
|
|
|
// return our new hash
|
|
*ppHash = pHash;
|
|
pHash = NULL;
|
|
|
|
error:
|
|
ReleaseObj(pHash);
|
|
return hr;
|
|
}
|