// -------------------------------------------------------------------------------- // Mhtmlurl.cpp // Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved // Steven J. Bailey // -------------------------------------------------------------------------------- #include "pch.hxx" #include "mhtmlurl.h" #include "icoint.h" #include "dllmain.h" #include "booktree.h" #include "shlwapi.h" #include "shlwapip.h" #include #include "icdebug.h" #include "stmlock.h" #include "strconst.h" #include "mimeapi.h" // -------------------------------------------------------------------------------- // TraceProtocol // -------------------------------------------------------------------------------- #define TraceProtocol(_pszFunction) \ DOUTL(APP_DOUTL, "%08x > 0x%08X CActiveUrlRequest::%s (RootUrl = '%s', BodyUrl = '%s')", GetCurrentThreadId(), this, _pszFunction, m_pszRootUrl ? m_pszRootUrl : "", m_pszBodyUrl ? m_pszBodyUrl : "") // -------------------------------------------------------------------------------- // AcitveUrlRequest_CreateInstance // -------------------------------------------------------------------------------- HRESULT IMimeHtmlProtocol_CreateInstance(IUnknown *pUnkOuter, IUnknown** ppUnknown) { // Invalid Arg Assert(ppUnknown); // Initialize *ppUnknown = NULL; // Set the mimeole compat mode MimeOleSetCompatMode(MIMEOLE_COMPAT_OE5); // Create me CActiveUrlRequest *pNew = new CActiveUrlRequest(pUnkOuter); if (NULL == pNew) return TrapError(E_OUTOFMEMORY); // Return the Innter *ppUnknown = pNew->GetInner(); // Done return S_OK; } // -------------------------------------------------------------------------------- // CActiveUrlRequest::CActiveUrlRequest // -------------------------------------------------------------------------------- CActiveUrlRequest::CActiveUrlRequest(IUnknown *pUnkOuter) : CPrivateUnknown(pUnkOuter) { DllAddRef(); m_pProtSink = NULL; m_pBindInfo = NULL; m_pszRootUrl = NULL; m_pszBodyUrl = NULL; m_pUnkKeepAlive = NULL; m_pNext = NULL; m_pPrev = NULL; m_dwState = 0; m_pStream = NULL; m_hNeedFile = INVALID_HANDLE_VALUE; m_dwBSCF = 0; InitializeCriticalSection(&m_cs); TraceProtocol("CActiveUrlRequest"); } // -------------------------------------------------------------------------------- // CActiveUrlRequest::~CActiveUrlRequest // -------------------------------------------------------------------------------- CActiveUrlRequest::~CActiveUrlRequest(void) { // Tracing TraceProtocol("~CActiveUrlRequest"); // These should have been release in IOInetProtocl::Terminate Assert(NULL == m_pProtSink && NULL == m_pBindInfo && NULL == m_pUnkKeepAlive); // Release the protcol object just in case SafeRelease(m_pProtSink); SafeRelease(m_pBindInfo); SafeMemFree(m_pszRootUrl); SafeMemFree(m_pszBodyUrl); SafeRelease(m_pUnkKeepAlive); SafeRelease(m_pStream); // Close file... if (INVALID_HANDLE_VALUE != m_hNeedFile) CloseHandle(m_hNeedFile); // Kill the CS DeleteCriticalSection(&m_cs); // Release the Dll DllRelease(); } // -------------------------------------------------------------------------------- // CActiveUrlRequest::PrivateQueryInterface // -------------------------------------------------------------------------------- HRESULT CActiveUrlRequest::PrivateQueryInterface(REFIID riid, LPVOID *ppv) { // Locals HRESULT hr=S_OK; // check params if (ppv == NULL) return TrapError(E_INVALIDARG); // Init *ppv = NULL; // Find IID if (IID_IOInetProtocol == riid) *ppv = (IOInetProtocol *)this; else if (IID_IOInetProtocolInfo == riid) *ppv = (IOInetProtocolInfo *)this; else if (IID_IOInetProtocolRoot == riid) *ppv = (IOInetProtocolRoot *)this; else if (IID_IServiceProvider == riid) *ppv = (IServiceProvider *)this; else { hr = TrapError(E_NOINTERFACE); goto exit; } // AddRef It ((IUnknown *)*ppv)->AddRef(); exit: // Done return hr; } // -------------------------------------------------------------------------------- // CActiveUrlRequest::_HrInitializeNeedFile // -------------------------------------------------------------------------------- HRESULT CActiveUrlRequest::_HrInitializeNeedFile(LPMESSAGETREE pTree, HBODY hBody) { // Locals HRESULT hr=S_OK; CHAR szFilePath[MAX_PATH + MAX_PATH]; ULONG cch; LPSTR pszFilePath=NULL; LPWSTR pwszFile=NULL; // Invalid Args Assert(INVALID_HANDLE_VALUE == m_hNeedFile); // Don't need a file ? if (FALSE == ISFLAGSET(m_dwState, REQSTATE_BINDF_NEEDFILE)) goto exit; // Set sizeof szFilePath cch = ARRAYSIZE(szFilePath); // If cid: if (!m_pszBodyUrl || StrCmpNIA(m_pszBodyUrl, "cid:", 4) == 0 || FAILED(PathCreateFromUrlA(m_pszBodyUrl, szFilePath, &cch, 0))) { // Create temp file (m_pszFileName could be null) CHECKHR(hr = CreateTempFile(NULL, NULL, &pszFilePath, &m_hNeedFile)); } else { // Create temp file CHECKHR(hr = CreateTempFile(szFilePath, NULL, &pszFilePath, &m_hNeedFile)); } // Convert To Unicode CHECKALLOC(pwszFile = PszToUnicode(CP_ACP, pszFilePath)); // Enter global Critical Section DeleteTempFileOnShutdownEx(pszFilePath, NULL); // Don't Free this pszFilePath = NULL; // Report the File... SideAssert(SUCCEEDED(m_pProtSink->ReportProgress(BINDSTATUS_CACHEFILENAMEAVAILABLE, pwszFile))); exit: // Cleanup SafeMemFree(pwszFile); SafeMemFree(pszFilePath); // Done return hr; } // -------------------------------------------------------------------------------- // CActiveUrlRequest::OnFullyAvailable // -------------------------------------------------------------------------------- void CActiveUrlRequest::OnFullyAvailable(LPCWSTR pszCntType, IStream *pStream, LPMESSAGETREE pTree, HBODY hBody) { // Locals HRESULT hr=S_OK; ULONG cb; // Invalid Arg Assert(pszCntType && pStream); // Thread Safety EnterCriticalSection(&m_cs); // Validate the state Assert(m_pProtSink && pStream && NULL == m_pStream); // Tracing TraceProtocol("OnFullyAvailable"); // Feed the content-type to trident m_pProtSink->ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE, pszCntType); // GetNeedFile CHECKHR(hr = _HrInitializeNeedFile(pTree, hBody)); // Create Stream Lock wrapper m_pStream = pStream; m_pStream->AddRef(); // Rewind that bad boy CHECKHR(hr = HrRewindStream(m_pStream)); // Were complete FLAGSET(m_dwState, REQSTATE_DOWNLOADED); // Initialize bind status callback falgs m_dwBSCF = BSCF_DATAFULLYAVAILABLE | BSCF_AVAILABLEDATASIZEUNKNOWN | BSCF_FIRSTDATANOTIFICATION | BSCF_INTERMEDIATEDATANOTIFICATION | BSCF_LASTDATANOTIFICATION; // Go into report data loop CHECKHR(hr = _HrReportData()); // First Report Data if (m_pProtSink) m_pProtSink->ReportResult(S_OK, 0, NULL); // We have reported the result FLAGSET(m_dwState, REQSTATE_RESULTREPORTED); exit: // Failure if (FAILED(hr)) _ReportResult(hr); // Thread Safety LeaveCriticalSection(&m_cs); } // -------------------------------------------------------------------------------- // CActiveUrlRequest::OnStartBinding // -------------------------------------------------------------------------------- void CActiveUrlRequest::OnStartBinding(LPCWSTR pszCntType, IStream *pStream, LPMESSAGETREE pTree, HBODY hBody) { // Locals HRESULT hr=S_OK; // Thread Safety EnterCriticalSection(&m_cs); // Validate the state Assert(m_pProtSink && pStream && NULL == m_pStream); // Tracing TraceProtocol("OnBinding(pszCntType, pStream)"); // Feed the content-type to trident m_pProtSink->ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE, pszCntType ? pszCntType : L"application/octet-stream"); // GetNeedFile CHECKHR(hr = _HrInitializeNeedFile(pTree, hBody)); // Create Stream Lock wrapper m_pStream = pStream; m_pStream->AddRef(); // Rewind that bad boy CHECKHR(hr = HrRewindStream(m_pStream)); // Initialize bind status callback falgs m_dwBSCF = BSCF_AVAILABLEDATASIZEUNKNOWN | BSCF_FIRSTDATANOTIFICATION; // Go into report data loop, if not writing to needfile (needfile is processed only when all the data is available) if (FALSE == ISFLAGSET(m_dwState, REQSTATE_BINDF_NEEDFILE)) { // Report me some data CHECKHR(hr = _HrReportData()); } exit: // Failure if (FAILED(hr)) _ReportResult(hr); // Thread Safety LeaveCriticalSection(&m_cs); } // -------------------------------------------------------------------------------- // CActiveUrlRequest::OnBindingDataAvailable // -------------------------------------------------------------------------------- void CActiveUrlRequest::OnBindingDataAvailable(void) { // Locals HRESULT hr=S_OK; // Thread Safety EnterCriticalSection(&m_cs); // Validate the state Assert(m_pProtSink && m_pStream); // Tracing TraceProtocol("OnBindingDataAvailable"); // Initialize bind status callback falgs FLAGSET(m_dwBSCF, BSCF_INTERMEDIATEDATANOTIFICATION); // Go into report data loop, if not writing to needfile (needfile is processed only when all the data is available) if (FALSE == ISFLAGSET(m_dwState, REQSTATE_BINDF_NEEDFILE)) { // Report some data CHECKHR(hr = _HrReportData()); } exit: // Failure if (FAILED(hr)) _ReportResult(hr); // Thread Safety LeaveCriticalSection(&m_cs); } // -------------------------------------------------------------------------------- // CActiveUrlRequest::OnBindingComplete // -------------------------------------------------------------------------------- void CActiveUrlRequest::OnBindingComplete(HRESULT hrResult) { // Locals HRESULT hr=S_OK; // Thread Safety EnterCriticalSection(&m_cs); // Were complete FLAGSET(m_dwState, INETPROT_DOWNLOADED); // Tracing TraceProtocol("OnBindingComplete"); // No Sink ? if (NULL == m_pProtSink) return; // Failure if (FAILED(hrResult)) { _ReportResult(hrResult); goto exit; } // Initialize bind status callback falgs m_dwBSCF = BSCF_DATAFULLYAVAILABLE | BSCF_AVAILABLEDATASIZEUNKNOWN | BSCF_FIRSTDATANOTIFICATION | BSCF_INTERMEDIATEDATANOTIFICATION | BSCF_LASTDATANOTIFICATION; // Report last amount of data CHECKHR(hr = _HrReportData()); // Tell sink to use the default protocol m_pProtSink->ReportResult(S_OK, 0, NULL); // We have reported the result FLAGSET(m_dwState, REQSTATE_RESULTREPORTED); exit: // Failure if (FAILED(hr)) _ReportResult(hr); // Thread Safety LeaveCriticalSection(&m_cs); } // -------------------------------------------------------------------------------- // CActiveUrlRequest::_ReportResult // -------------------------------------------------------------------------------- void CActiveUrlRequest::_ReportResult(HRESULT hrResult) { // Locals LPWSTR pwszRedirUrl=NULL; // We should have a sink Assert(m_pProtSink); // No Sink ? if (m_pProtSink && !ISFLAGSET(m_dwState, REQSTATE_RESULTREPORTED)) { // If Failure if (FAILED(hrResult)) { // If we have a body Url if (m_pszBodyUrl) pwszRedirUrl = PszToUnicode(CP_ACP, m_pszBodyUrl); // Report Result, if (pwszRedirUrl) { TraceProtocol("_ReportResult(BINDSTATUS_REDIRECTING)"); m_pProtSink->ReportResult(INET_E_REDIRECTING, 0, pwszRedirUrl); } else { TraceProtocol("_ReportResult(INET_E_USE_DEFAULT_PROTOCOLHANDLER)"); m_pProtSink->ReportResult(INET_E_USE_DEFAULT_PROTOCOLHANDLER, 0, NULL); } } // Otherwise, report the result else { TraceProtocol("_ReportResult(INET_E_USE_DEFAULT_PROTOCOLHANDLER)"); m_pProtSink->ReportResult(S_OK, 0, NULL); } // Cleanup SafeMemFree(pwszRedirUrl); // We have reported the result FLAGSET(m_dwState, REQSTATE_RESULTREPORTED); } } // -------------------------------------------------------------------------------- // CActiveUrlRequest::_HrReportData // -------------------------------------------------------------------------------- HRESULT CActiveUrlRequest::_HrReportData(void) { // Locals HRESULT hr=S_OK; // We better have a data source Assert(m_pStream); // Tracing TraceProtocol("_HrReportData"); // BINDF_NEEDFILE if (ISFLAGSET(m_dwState, REQSTATE_BINDF_NEEDFILE)) { // Dump to File CHECKHR(hr = _HrStreamToNeedFile()); } else { // Report Data SideAssert(SUCCEEDED(m_pProtSink->ReportData(m_dwBSCF, 0, 0))); } exit: // Done return hr; } // -------------------------------------------------------------------------------- // CActiveUrlRequest::_HrStreamToNeedFile // -------------------------------------------------------------------------------- HRESULT CActiveUrlRequest::_HrStreamToNeedFile(void) { // Locals HRESULT hr=S_OK; ULONG cbTotal=0; // We better have a needfile Assert(INVALID_HANDLE_VALUE != m_hNeedFile && ISFLAGSET(m_dwState, REQSTATE_DOWNLOADED)); // Write the stream to a file hr = WriteStreamToFileHandle(m_pStream, m_hNeedFile, &cbTotal); if (FAILED(hr) && E_PENDING != hr) { TrapError(hr); goto exit; } // Close the 77file CloseHandle(m_hNeedFile); m_hNeedFile = INVALID_HANDLE_VALUE; // Rewind the stream incase urlmon trys to read from me as well HrRewindStream(m_pStream); // All the data is there SideAssert(SUCCEEDED(m_pProtSink->ReportData(m_dwBSCF, 0, 0))); exit: // Done return hr; } // -------------------------------------------------------------------------------- // CActiveUrlRequest::Start // -------------------------------------------------------------------------------- STDMETHODIMP CActiveUrlRequest::Start(LPCWSTR pwszUrl, IOInetProtocolSink *pProtSink, IOInetBindInfo *pBindInfo, DWORD grfSTI, HANDLE_PTR dwReserved) { // Locals HRESULT hr=S_OK; LPSTR pszUrl=NULL; LPMESSAGETREE pTree=NULL; DWORD dwBindF; BINDINFO rBindInfo; // Invalid Args if (NULL == pwszUrl || NULL == pProtSink || NULL == pBindInfo) return TrapError(E_INVALIDARG); // Thread Safety EnterCriticalSection(&m_cs); // Check State Assert(g_pUrlCache && m_pProtSink == NULL && m_pBindInfo == NULL); // BINDF_NEEDFILE ZeroMemory(&rBindInfo, sizeof(BINDINFO)); rBindInfo.cbSize = sizeof(BINDINFO); if (SUCCEEDED(pBindInfo->GetBindInfo(&dwBindF, &rBindInfo)) && ISFLAGSET(dwBindF, BINDF_NEEDFILE)) { // Set Flag FLAGSET(m_dwState, REQSTATE_BINDF_NEEDFILE); } // Assume the Sink m_pProtSink = pProtSink; m_pProtSink->AddRef(); // Assume the BindInfo m_pBindInfo = pBindInfo; m_pBindInfo->AddRef(); // Dup the Url CHECKALLOC(pszUrl = PszToANSI(CP_ACP, pwszUrl)); // Unescape inplace CHECKHR(hr = UrlUnescapeA(pszUrl, NULL, NULL, URL_UNESCAPE_INPLACE)); // Split the Url CHECKHR(hr = MimeOleParseMhtmlUrl(pszUrl, &m_pszRootUrl, &m_pszBodyUrl)); // for security purposes, disallow navigate using the mhtml protocl in IE except with correct ext // wait to do this check until after we have a protocol sink to report the error and we've parsed // out the root url if (StrCmpNI(m_pszRootUrl, TEXT("mid:"), 4) && GetModuleHandle(TEXT("IEXPLORE.EXE"))) { LPTSTR pszExt = PathFindExtension(m_pszRootUrl); if (!pszExt || (StrCmpI(pszExt, TEXT(".mht")) && StrCmpI(pszExt, TEXT(".mhtml")))) { hr = INET_E_SECURITY_PROBLEM; goto exit; } } // Tracing TraceProtocol("Start"); // Try to resolve the root url CHECKHR(hr = g_pUrlCache->ActiveObjectFromUrl(m_pszRootUrl, TRUE, IID_CMessageTree, (LPVOID *)&pTree, &m_pUnkKeepAlive)); // Ask the BindTree to Resolve this Url CHECKHR(hr = pTree->HrActiveUrlRequest(this)); exit: // Cleanup SafeMemFree(pszUrl); SafeRelease(pTree); // Failure //if (FAILED(hr)) // _ReportResult(E_FAIL); // Thread Safety LeaveCriticalSection(&m_cs); // Done return hr; } // -------------------------------------------------------------------------------- // CActiveUrlRequest::Terminate // -------------------------------------------------------------------------------- STDMETHODIMP CActiveUrlRequest::Terminate(DWORD dwOptions) { // Thread Safety EnterCriticalSection(&m_cs); // Tracing TraceProtocol("Terminate"); // Release Objects SafeRelease(m_pProtSink); SafeRelease(m_pBindInfo); SafeRelease(m_pUnkKeepAlive); // Thread Safety LeaveCriticalSection(&m_cs); // Done return S_OK; } // -------------------------------------------------------------------------------- // CActiveUrlRequest::Read (IOInetProtocol) // -------------------------------------------------------------------------------- STDMETHODIMP CActiveUrlRequest::Read(LPVOID pv,ULONG cb, ULONG *pcbRead) { // Locals HRESULT hr=S_OK; ULONG cbRead; // Init if (pcbRead) *pcbRead = 0; // No Stream Yet if (NULL == m_pStream) { Assert(FALSE); hr = TrapError(E_FAIL); goto exit; } // Read from the external offset CHECKHR(hr = m_pStream->Read(pv, cb, &cbRead)); // Done if (0 == cbRead) { // S_FALSE = Were Done, E_PENDING = more data is coming hr = (ISFLAGSET(m_dwState, INETPROT_DOWNLOADED)) ? S_FALSE : E_PENDING; } // Otherwise, set to ok else hr = S_OK; // Return pcbRead if (pcbRead) *pcbRead = cbRead; exit: // Done return hr; } // -------------------------------------------------------------------------------- // CActiveUrlRequest::Seek (IOInetProtocol) // -------------------------------------------------------------------------------- STDMETHODIMP CActiveUrlRequest::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNew) { // Locals HRESULT hr=S_OK; // Thread Safety EnterCriticalSection(&m_cs); // Tracing TraceProtocol("Seek"); // No Stream Yet if (NULL == m_pStream) { Assert(FALSE); hr = TrapError(E_FAIL); goto exit; } // Call Utility Function CHECKHR(hr = m_pStream->Seek(dlibMove, dwOrigin, plibNew)); exit: // Thread Safety LeaveCriticalSection(&m_cs); // Done return hr; } // -------------------------------------------------------------------------------- // CActiveUrlRequest::QueryService // -------------------------------------------------------------------------------- STDMETHODIMP CActiveUrlRequest::QueryService(REFGUID rsid, REFIID riid, void **ppvObject) /* IServiceProvider */ { // Locals HRESULT hr=S_OK; IServiceProvider *pSP=NULL; // Thread Safety EnterCriticalSection(&m_cs); // Tracing TraceProtocol("QueryService"); // No Protocol Sink Yet ? if (NULL == m_pProtSink) { hr = TrapError(E_UNEXPECTED); goto exit; } // QI the Sink for the IServiceProvider CHECKHR(hr = m_pProtSink->QueryInterface(IID_IServiceProvider, (LPVOID *)&pSP)); // Query Service the Service Provider CHECKHR(hr = pSP->QueryService(rsid, riid, ppvObject)); exit: // Cleanup SafeRelease(pSP); // Thread Safety LeaveCriticalSection(&m_cs); // Done return hr; } // -------------------------------------------------------------------------------- // CActiveUrlRequest::_FillReturnString // -------------------------------------------------------------------------------- HRESULT CActiveUrlRequest::_FillReturnString(LPCWSTR pszUrl, DWORD cchUrl, LPWSTR pszResult, DWORD cchResult, DWORD *pcchResult) { // Locals HRESULT hr=S_OK; // Want the Size if (pcchResult) *pcchResult = cchUrl; // No return value if (NULL == pszResult) goto exit; // Dest is big enought if (cchResult < cchUrl+1) { hr = TrapError(E_FAIL); goto exit; } // Copy to dest buffer CopyMemory((LPBYTE)pszResult, (LPBYTE)pszUrl, ((cchUrl + 1) * sizeof(WCHAR))); exit: // Done return hr; } // -------------------------------------------------------------------------------- // CActiveUrlRequest::ParseUrl // -------------------------------------------------------------------------------- STDMETHODIMP CActiveUrlRequest::ParseUrl(LPCWSTR pwzUrl, PARSEACTION ParseAction, DWORD dwParseFlags, LPWSTR pwzResult, DWORD cchResult, DWORD *pcchResult, DWORD dwReserved) { // Locals HRESULT hr=S_OK; ULONG cchUrl; LPSTR pszUrl=NULL; LPSTR pszRootUrl=NULL; LPSTR pszBodyUrl=NULL; LPWSTR pwszBodyUrl=NULL; LPWSTR pszRootUrlW=NULL; LPWSTR pszSecurityUrlW=NULL; PROPVARIANT rVariant; // Invalid Arg if (NULL == pwzUrl) return TrapError(E_INVALIDARG); // Tracing DOUTL(APP_DOUTL, "%08X > 0x%08X CActiveUrlRequest::ParseUrl (pwzUrl = %ls)", GetCurrentThreadId(), this, pwzUrl); // Setup Variant ZeroMemory(&rVariant, sizeof(PROPVARIANT)); // Only handle PARSE_CANONICALIZE if (PARSE_CANONICALIZE == ParseAction) { // Fill return value CHECKHR(hr = _FillReturnString(pwzUrl, lstrlenW(pwzUrl), pwzResult, cchResult, pcchResult)); } // Strip MHTML: and return #ifndef WIN16 else if (StrCmpNIW(pwzUrl, L"mhtml:", 6) == 0) #else else if (StrCmpNIW(pwzUrl, "mhtml:", 6) == 0) #endif // !WIN16 { // If Getting Friendly if (PARSE_FRIENDLY == ParseAction) { // To ANSI CHECKALLOC(pszUrl = PszToANSI(CP_ACP, pwzUrl)); // Split It CHECKHR(hr = MimeOleParseMhtmlUrl(pszUrl, &pszRootUrl, &pszBodyUrl)); // Convert To Unicode CHECKALLOC(pwszBodyUrl = PszToUnicode(CP_ACP, pszBodyUrl)); // Fill return value CHECKHR(hr = _FillReturnString(pwszBodyUrl, lstrlenW(pwszBodyUrl), pwzResult, cchResult, pcchResult)); } // If the content-location is available, use it as the security URL else if (PARSE_SECURITY_URL == ParseAction) { BOOL fGotSecURL = FALSE; LPMESSAGETREE pTree=NULL; HBODY hBody; IInternetSecurityManager *pISM; DWORD dwZone=URLZONE_UNTRUSTED; // Base to ANSI CHECKALLOC(pszUrl = PszToANSI(CP_ACP, pwzUrl)); // UnEscape the Url CHECKHR(hr = UrlUnescapeA(pszUrl, NULL, NULL, URL_UNESCAPE_INPLACE)); // Split It CHECKHR(hr = MimeOleParseMhtmlUrl(pszUrl, &pszRootUrl, &pszBodyUrl)); // RootUrl to UNICODE CHECKALLOC(pszRootUrlW = PszToUnicode(CP_ACP, pszRootUrl)); // Check and see what ZONE the root url is running in if (CoInternetCreateSecurityManager(NULL, &pISM, 0)==S_OK) { pISM->MapUrlToZone(pszRootUrlW, &dwZone, 0); pISM->Release(); } // default to the root-body part pszSecurityUrlW = pszRootUrlW; // if the root url is in the local-machine, then respect the Content-Location header // as the source of the url, otherwise defer to the root url if ((dwZone == URLZONE_LOCAL_MACHINE) && SUCCEEDED(g_pUrlCache->ActiveObjectFromUrl(pszRootUrl, FALSE, IID_CMessageTree, (LPVOID *)&pTree, NULL))) { if ( (pszBodyUrl != NULL && SUCCEEDED(pTree->ResolveURL(NULL, NULL, pszBodyUrl, 0, &hBody))) || SUCCEEDED(pTree->GetTextBody(TXT_HTML, IET_BINARY, NULL, &hBody))) { // Locals LPWSTR pwszSecURL = NULL; PSUACTION psua = (dwParseFlags == PSU_SECURITY_URL_ONLY)? PSU_SECURITY_URL_ONLY: PSU_DEFAULT; rVariant.vt = VT_LPWSTR; if (SUCCEEDED(pTree->GetBodyProp(hBody, PIDTOSTR(PID_HDR_CNTLOC), NOFLAGS, &rVariant)) && rVariant.pwszVal && *rVariant.pwszVal) { pszSecurityUrlW = rVariant.pwszVal; } SafeMemFree(pwszSecURL); } } // Fill return value CHECKHR(hr = _FillReturnString(pszSecurityUrlW, lstrlenW(pszSecurityUrlW), pwzResult, cchResult, pcchResult)); SafeRelease(pTree); } else if (PARSE_ENCODE == ParseAction) { hr = INET_E_DEFAULT_ACTION; } // Simply remove mhtml: else { // Fill return value CHECKHR(hr = _FillReturnString(pwzUrl + 6, lstrlenW(pwzUrl) - 6, pwzResult, cchResult, pcchResult)); } } // INET_E_DEFAULT_ACTION else { hr = INET_E_DEFAULT_ACTION; goto exit; } exit: // Cleanup SafeMemFree(pszUrl); SafeMemFree(pszRootUrl); SafeMemFree(pszRootUrlW); SafeMemFree(pszBodyUrl); SafeMemFree(pwszBodyUrl); SafeMemFree(rVariant.pwszVal); // Done return hr; } // -------------------------------------------------------------------------------- // CActiveUrlRequest::QueryInfo // -------------------------------------------------------------------------------- STDMETHODIMP CActiveUrlRequest::QueryInfo(LPCWSTR pwzUrl, QUERYOPTION OueryOption, DWORD dwQueryFlags, LPVOID pBuffer, DWORD cbBuffer, DWORD *pcbBuf, DWORD dwReserved) { // QUERY_RECOMBINE if (QUERY_RECOMBINE == OueryOption) { // Sure if (cbBuffer < sizeof(DWORD)) return S_FALSE; // True DWORD dw=TRUE; CopyMemory(pBuffer, &dw, sizeof(dw)); *pcbBuf = sizeof(dw); // Done return S_OK; } // Failure return INET_E_QUERYOPTION_UNKNOWN; } // -------------------------------------------------------------------------------- // CActiveUrlRequest::CombineUrl // -------------------------------------------------------------------------------- STDMETHODIMP CActiveUrlRequest::CombineUrl(LPCWSTR pwzBaseUrl, LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags, LPWSTR pwzResult, DWORD cchResult, DWORD *pcchResult, DWORD dwReserved) { // Locals HRESULT hr=S_OK; LPSTR pszBaseUrl=NULL; LPSTR pszRootUrl=NULL; LPSTR pszBodyUrl=NULL; LPSTR pszRelativeUrl=NULL; LPSTR pszNewUrl=NULL; LPSTR pszDocUrl=NULL; LPSTR pszPageUrl=NULL; LPWSTR pwszBodyUrl=NULL; LPWSTR pwszNewUrl=NULL; LPWSTR pwszSource=NULL; BOOL fCombine=FALSE; LPMESSAGETREE pTree=NULL; ULONG cchSource; ULONG cchPrefix=lstrlen(c_szMHTMLColon); HBODY hBody; // Invalid Arg if (NULL == pwzRelativeUrl) return TrapError(E_INVALIDARG); // Thread Safety EnterCriticalSection(&m_cs); // DebugTraceing #ifndef WIN16 DOUTL(APP_DOUTL, "%08X > 0x%08X CActiveUrlRequest::CombineUrl - Base = %ls, Relative = %ls", GetCurrentThreadId(), this, pwzBaseUrl ? pwzBaseUrl : L"" , pwzRelativeUrl ? pwzRelativeUrl : L""); #else DOUTL(APP_DOUTL, "%08X > 0x%08X CActiveUrlRequest::CombineUrl - Base = %ls, Relative = %ls", GetCurrentThreadId(), this, pwzBaseUrl ? pwzBaseUrl : "" , pwzRelativeUrl ? pwzRelativeUrl : ""); #endif // !WIN16 // Raid-42722: MHTML: Bookmarks don't work if (L'#' == pwzRelativeUrl[0]) { hr = E_FAIL; goto exit; } // Convert relative to ANSI CHECKALLOC(pszRelativeUrl = PszToANSI(CP_ACP, pwzRelativeUrl)); // We should UnEscape only Url, but doesn't touch a query CHECKHR(hr = UrlUnescapeA(pszRelativeUrl, NULL, NULL, URL_UNESCAPE_INPLACE | URL_DONT_ESCAPE_EXTRA_INFO)); // If the relative is already mhtml:, then retur that... if (StrCmpNI(pszRelativeUrl, c_szMHTMLColon, cchPrefix) == 0) { // Split It CHECKHR(hr = MimeOleParseMhtmlUrl(pszRelativeUrl, &pszRootUrl, &pszBodyUrl)); // If no body url, then just return pszRelativeUrl if (NULL == pszBodyUrl) { // Set pwszSource pwszSource = (LPWSTR)(pwzRelativeUrl + cchPrefix); // Get Length cchSource = lstrlenW(pwzRelativeUrl) - cchPrefix; // Done goto set_return; } } // Otherwise, build a new url else { // Base to ANSI CHECKALLOC(pszBaseUrl = PszToANSI(CP_ACP, pwzBaseUrl)); // UnEscape the Url CHECKHR(hr = UrlUnescapeA(pszBaseUrl, NULL, NULL, URL_UNESCAPE_INPLACE)); // Split It CHECKHR(hr = MimeOleParseMhtmlUrl(pszBaseUrl, &pszRootUrl, &pszPageUrl)); // Set pszBodyUrl pszBodyUrl = pszRelativeUrl; // Don't need pszRelativeUrl anymore pszRelativeUrl = NULL; } // Better have a root and a body url Assert(pszRootUrl && pszBodyUrl); // Try to resolve the root url if (SUCCEEDED(g_pUrlCache->ActiveObjectFromUrl(pszRootUrl, FALSE, IID_CMessageTree, (LPVOID *)&pTree, NULL))) { // If pszBodyUrl is in the WebBook or the bind is not finished...then do the url combine if (SUCCEEDED(pTree->ResolveURL(NULL, NULL, pszBodyUrl, 0, NULL)) || pTree->IsState(TREESTATE_BINDDONE) == S_FALSE) { // Combine the Urls fCombine = TRUE; } // fCombine = TRUE; } // Should we combine if (fCombine) { // Allocate Some Memory DWORD cchSize = (cchPrefix + lstrlen(pszRootUrl) + lstrlen(pszBodyUrl) + 2); CHECKALLOC(pszNewUrl = PszAllocA(cchSize)); // Format the string wnsprintfA(pszNewUrl, cchSize, "%s%s!%s", c_szMHTMLColon, pszRootUrl, pszBodyUrl); // Convert to unicode CHECKALLOC(pwszNewUrl = PszToUnicode(CP_ACP, pszNewUrl)); // Get length cchSource = lstrlenW(pwszNewUrl); // Set Source pwszSource = pwszNewUrl; } // No Combine else { // If we have a WebBook if (pTree) { // If we don't have a page Url, then just call GetTextBody(html) if (NULL == pszPageUrl) MimeOleComputeContentBase(pTree, NULL, &pszDocUrl, NULL); // Otherwise, try to resolve the page url else if (SUCCEEDED(pTree->ResolveURL(NULL, NULL, pszPageUrl, 0, &hBody))) pszDocUrl = MimeOleContentBaseFromBody(pTree, hBody); // If we have Url if (pszDocUrl) { // Unescape It CHECKHR(hr = UrlUnescapeA(pszDocUrl, NULL, NULL, URL_UNESCAPE_INPLACE)); } // Otheriwse, if the WebBook was loaded by a moniker, then use pszRootUrl else if (pTree->IsState(TREESTATE_LOADEDBYMONIKER) == S_OK) { // pszRootUrl is the pszDocUrl CHECKALLOC(pszDocUrl = PszDupA(pszRootUrl)); } } // If there is a pszDocUrl if (pszDocUrl) { // Lets Combine with this url CHECKHR(hr = MimeOleCombineURL(pszDocUrl, lstrlen(pszDocUrl), pszBodyUrl, lstrlen(pszBodyUrl), FALSE, &pszNewUrl)); // Convert to unicode CHECKALLOC(pwszNewUrl = PszToUnicode(CP_ACP, pszNewUrl)); // Get length cchSource = lstrlenW(pwszNewUrl); // Set Source pwszSource = pwszNewUrl; } else { // Need a wide body Url CHECKALLOC(pwszBodyUrl = PszToUnicode(CP_ACP, pszBodyUrl)); // Get length cchSource = lstrlenW(pwszBodyUrl); // Set Source pwszSource = pwszBodyUrl; } } set_return: // Set Dest Size if (pcchResult) *pcchResult = cchSource; // No return value if (NULL == pwzResult) goto exit; // Dest is big enought if (cchResult <= cchSource) { hr = TrapError(E_FAIL); goto exit; } // Copy to dest buffer CopyMemory((LPBYTE)pwzResult, (LPBYTE)pwszSource, ((cchSource + 1) * sizeof(WCHAR))); exit: // Cleanup SafeMemFree(pszRootUrl); SafeMemFree(pszRelativeUrl); SafeMemFree(pszBodyUrl); SafeMemFree(pszNewUrl); SafeMemFree(pwszNewUrl); SafeMemFree(pszBaseUrl); SafeMemFree(pszDocUrl); SafeMemFree(pwszBodyUrl); SafeMemFree(pszPageUrl); SafeRelease(pTree); // Thread Safety LeaveCriticalSection(&m_cs); // Done return hr; } // -------------------------------------------------------------------------------- // CActiveUrl::CActiveUrl // -------------------------------------------------------------------------------- CActiveUrl::CActiveUrl(void) { m_cRef = 1; m_pUnkAlive = NULL; m_pUnkInner = NULL; m_pWebBook = NULL; m_pNext = NULL; m_pPrev = NULL; m_dwFlags = 0; InitializeCriticalSection(&m_cs); } // -------------------------------------------------------------------------------- // CActiveUrl::~CActiveUrl // -------------------------------------------------------------------------------- CActiveUrl::~CActiveUrl(void) { SafeRelease(m_pUnkAlive); DeleteCriticalSection(&m_cs); } // -------------------------------------------------------------------------------- // CActiveUrl::QueryInterface // -------------------------------------------------------------------------------- STDMETHODIMP CActiveUrl::QueryInterface(REFIID riid, LPVOID *ppv) { // Locals HRESULT hr=S_OK; // check params if (ppv == NULL) return TrapError(E_INVALIDARG); // Find IID if (IID_IUnknown == riid) *ppv = (IUnknown *)this; else { *ppv = NULL; hr = TrapError(E_NOINTERFACE); goto exit; } // AddRef It ((IUnknown *)*ppv)->AddRef(); exit: // Done return hr; } // -------------------------------------------------------------------------------- // CActiveUrl::AddRef // -------------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CActiveUrl::AddRef(void) { return (ULONG)InterlockedIncrement(&m_cRef); } // -------------------------------------------------------------------------------- // CActiveUrl::Release // -------------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CActiveUrl::Release(void) { LONG cRef = InterlockedDecrement(&m_cRef); if (0 == cRef) delete this; return (ULONG)cRef; } // -------------------------------------------------------------------------------- // CActiveUrl::Init // -------------------------------------------------------------------------------- HRESULT CActiveUrl::Init(BINDF bindf, LPMESSAGETREE pTree) { // Locals HRESULT hr=S_OK; // Thread Safety EnterCriticalSection(&m_cs); // Better not have data Assert(NULL == m_pWebBook && NULL == m_pUnkInner); // No Message Object Passed in ? if (NULL == pTree) { // Allocate the Message Object CHECKALLOC(pTree = new CMessageTree); // Set pMessage m_pUnkAlive = pTree->GetInner(); // Init CHECKHR(hr = pTree->InitNew()); } // Set BINDF_PRAGMA_NO_CACHE if (ISFLAGSET(bindf, BINDF_RESYNCHRONIZE)) { // Set State pTree->SetState(TREESTATE_RESYNCHRONIZE); } // Set pMessage m_pWebBook = pTree; // Get the Message Object's Inner Unknown m_pUnkInner = pTree->GetInner(); // Register pActiveUrl as a handle in the message object m_pWebBook->SetActiveUrl(this); exit: // Thread Safety LeaveCriticalSection(&m_cs); // Done return hr; } // -------------------------------------------------------------------------------- // CActiveUrl::DontKeepAlive // -------------------------------------------------------------------------------- void CActiveUrl::DontKeepAlive(void) { // Thread Safety EnterCriticalSection(&m_cs); // Set pMessage if (m_pUnkAlive) { // Somebody should still have a refcount on this dude SideAssert(m_pUnkAlive->Release() > 0); // Null It m_pUnkAlive = NULL; } // Thread Safety LeaveCriticalSection(&m_cs); } // -------------------------------------------------------------------------------- // CActiveUrl::IsActive // -------------------------------------------------------------------------------- HRESULT CActiveUrl::IsActive(void) { EnterCriticalSection(&m_cs); HRESULT hr = m_pWebBook ? S_OK : S_FALSE; LeaveCriticalSection(&m_cs); return hr; } // -------------------------------------------------------------------------------- // CActiveUrl::RevokeWebBook // -------------------------------------------------------------------------------- void CActiveUrl::RevokeWebBook(LPMESSAGETREE pTree) { // Thread Safety EnterCriticalSection(&m_cs); // Invalid Arg Assert(NULL == pTree || m_pWebBook == pTree); // Revoke This from the message if (m_pWebBook) m_pWebBook->SetActiveUrl(NULL); // Null m_pWebBook m_pWebBook = NULL; m_pUnkInner = NULL; // Check Ref Count Assert(1 == m_cRef); // Thread Safety LeaveCriticalSection(&m_cs); } // -------------------------------------------------------------------------------- // CActiveUrl::CompareRootUrl // -------------------------------------------------------------------------------- HRESULT CActiveUrl::CompareRootUrl(LPCSTR pszUrl) { // Thread Safety EnterCriticalSection(&m_cs); // Compare Root Url HRESULT hr = m_pWebBook ? m_pWebBook->CompareRootUrl(pszUrl) : S_FALSE; // Thread Safety LeaveCriticalSection(&m_cs); // Done return hr; } // -------------------------------------------------------------------------------- // CActiveUrl::BindToObject // -------------------------------------------------------------------------------- HRESULT CActiveUrl::BindToObject(REFIID riid, LPVOID *ppv) { // Thread Safety EnterCriticalSection(&m_cs); // Compare Root Url HRESULT hr = m_pUnkInner ? m_pUnkInner->QueryInterface(riid, ppv) : TrapError(E_FAIL); // Thread Safety LeaveCriticalSection(&m_cs); // Done return hr; } // -------------------------------------------------------------------------------- // CActiveUrl::CreateWebPage // -------------------------------------------------------------------------------- HRESULT CActiveUrl::CreateWebPage(IStream *pStmRoot, LPWEBPAGEOPTIONS pOptions, DWORD dwReserved, IMoniker **ppMoniker) { // Locals HRESULT hr=S_OK; // Thread Safety EnterCriticalSection(&m_cs); // No Message if (NULL == m_pWebBook) { hr = TrapError(E_FAIL); goto exit; } // CreateWebPage CHECKHR(hr = m_pWebBook->CreateWebPage(pStmRoot, pOptions, NULL, ppMoniker)); exit: // Thread Safety LeaveCriticalSection(&m_cs); // Done return hr; } // -------------------------------------------------------------------------------- // CMimeActiveUrlCache::CMimeActiveUrlCache // -------------------------------------------------------------------------------- CMimeActiveUrlCache::CMimeActiveUrlCache(void) { m_cRef = 1; m_cActive = 0; m_pHead = NULL; InitializeCriticalSection(&m_cs); } // -------------------------------------------------------------------------------- // CMimeActiveUrlCache::~CMimeActiveUrlCache // -------------------------------------------------------------------------------- CMimeActiveUrlCache::~CMimeActiveUrlCache(void) { _FreeActiveUrlList(TRUE); DeleteCriticalSection(&m_cs); } // -------------------------------------------------------------------------------- // CMimeActiveUrlCache::_FreeActiveUrlList // -------------------------------------------------------------------------------- void CMimeActiveUrlCache::_FreeActiveUrlList(BOOL fAll) { // Locals LPACTIVEURL pCurr; LPACTIVEURL pNext; // Init pCurr = m_pHead; // All if (fAll) { // Loop and Free while(pCurr) { // Set Next pNext = pCurr->PGetNext(); // Revoke the handle pCurr->RevokeWebBook(NULL); // Free the Active Url pCurr->Release(); // Goto Next pCurr = pNext; } // No Active m_cActive = 0; m_pHead = NULL; } else { // Loop and Free while(pCurr) { // Set Next pNext = pCurr->PGetNext(); // Revoke the handle if (pCurr->IsActive() == S_FALSE) _RemoveUrl(pCurr); // Goto Next pCurr = pNext; } } } // -------------------------------------------------------------------------------- // CMimeActiveUrlCache::QueryInterface // -------------------------------------------------------------------------------- STDMETHODIMP CMimeActiveUrlCache::QueryInterface(REFIID riid, LPVOID *ppv) { // Locals HRESULT hr=S_OK; // check params if (ppv == NULL) return TrapError(E_INVALIDARG); // Find IID if (IID_IUnknown == riid) *ppv = (IUnknown *)this; else { *ppv = NULL; hr = TrapError(E_NOINTERFACE); goto exit; } // AddRef It ((IUnknown *)*ppv)->AddRef(); exit: // Done return hr; } // -------------------------------------------------------------------------------- // CMimeActiveUrlCache::AddRef // -------------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CMimeActiveUrlCache::AddRef(void) { return (ULONG)InterlockedIncrement(&m_cRef); } // -------------------------------------------------------------------------------- // CMimeActiveUrlCache::Release // -------------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CMimeActiveUrlCache::Release(void) { LONG cRef = InterlockedDecrement(&m_cRef); if (0 == cRef) delete this; return (ULONG)cRef; } // -------------------------------------------------------------------------------- // CMimeActiveUrlCache::_RegisterUrl // -------------------------------------------------------------------------------- HRESULT CMimeActiveUrlCache::_RegisterUrl(LPMESSAGETREE pTree, BINDF bindf, LPACTIVEURL *ppActiveUrl) { // Locals HRESULT hr=S_OK; LPACTIVEURL pActiveUrl=NULL; // Invalid Arg Assert(ppActiveUrl); // Init *ppActiveUrl = NULL; // Allocate an ActiveUrl CHECKALLOC(pActiveUrl = new CActiveUrl); // Init the Active Url CHECKHR(hr = pActiveUrl->Init(bindf, pTree)); // Link Into Chain if (NULL == m_pHead) m_pHead = pActiveUrl; else { pActiveUrl->SetNext(m_pHead); m_pHead->SetPrev(pActiveUrl); m_pHead = pActiveUrl; } // Increment Count m_cActive++; // Return It *ppActiveUrl = pActiveUrl; pActiveUrl = NULL; exit: // Release the Active Url SafeRelease(pActiveUrl); // Done return hr; } // -------------------------------------------------------------------------------- // CMimeActiveUrlCache::_ResolveUrl // -------------------------------------------------------------------------------- HRESULT CMimeActiveUrlCache::_ResolveUrl(LPCSTR pszUrl, LPACTIVEURL *ppActiveUrl) { // Locals HRESULT hr=S_OK; LPACTIVEURL pActiveUrl; // Invalid Arg Assert(pszUrl && ppActiveUrl); // Init *ppActiveUrl = NULL; // Should not have mhtml: Assert(StrCmpNI(pszUrl, "mhtml:", 6) != 0); // Walk the Table for (pActiveUrl=m_pHead; pActiveUrl!=NULL; pActiveUrl=pActiveUrl->PGetNext()) { // Is this the Url if (pActiveUrl->CompareRootUrl(pszUrl) == S_OK) { // Return the Active Url *ppActiveUrl = pActiveUrl; // Done goto exit; } } // Not Found hr = TrapError(MIME_E_NOT_FOUND); exit: // Done return hr; } // -------------------------------------------------------------------------------- // CMimeActiveUrlCache::_RemoveUrl // -------------------------------------------------------------------------------- HRESULT CMimeActiveUrlCache::_RemoveUrl(LPACTIVEURL pActiveUrl) { EnterCriticalSection(&m_cs); // Fixup Linked List LPACTIVEURL pNext = pActiveUrl->PGetNext(); LPACTIVEURL pPrev = pActiveUrl->PGetPrev(); // Fixup if (pPrev) pPrev->SetNext(pNext); if (pNext) pNext->SetPrev(pPrev); // Fixup m_pHead if (m_pHead == pActiveUrl) m_pHead = pNext; // Revoke the handle pActiveUrl->RevokeWebBook(NULL); // Release the ActiveUrl SideAssert(0 == pActiveUrl->Release()); // One less active m_cActive--; LeaveCriticalSection(&m_cs); // Done return S_OK; } // -------------------------------------------------------------------------------- // CMimeActiveUrlCache::RemoveUrl // -------------------------------------------------------------------------------- HRESULT CMimeActiveUrlCache::RemoveUrl(LPACTIVEURL pActiveUrl) { return _RemoveUrl(pActiveUrl); } // -------------------------------------------------------------------------------- // CMimeActiveUrlCache::_HandlePragmaNoCache // -------------------------------------------------------------------------------- void CMimeActiveUrlCache::_HandlePragmaNoCache(BINDF bindf, LPCSTR pszUrl) { // Locals CActiveUrl *pActiveUrl; // Invalid Arg Assert(pszUrl); // BINDF_PRAGMA_NO_CACHE - Reload the WebBook from original source (can't do if activeurl has a fake url) if (ISFLAGSET((DWORD)bindf, BINDF_PRAGMA_NO_CACHE)) { // Try to find the ActiveUrl associated with pszUrl if (SUCCEEDED(_ResolveUrl(pszUrl, &pActiveUrl))) { // If it is a fakeurl, then lets not unload it if (FALSE == pActiveUrl->FIsFlagSet(ACTIVEURL_ISFAKEURL)) { // Kill it from the cache so that its not found and reloaded _RemoveUrl(pActiveUrl); } } } } // -------------------------------------------------------------------------------- // CMimeActiveUrlCache::ActiveObjectFromMoniker - Called from Trident // -------------------------------------------------------------------------------- HRESULT CMimeActiveUrlCache::ActiveObjectFromMoniker( /* in */ BINDF bindf, /* in */ IMoniker *pmkOriginal, /* in */ IBindCtx *pBindCtx, /* in */ REFIID riid, /* out */ LPVOID *ppvObject, /* out */ IMoniker **ppmkNew) { // Locals HRESULT hr=S_OK; LPWSTR pwszUrl=NULL; LPSTR pszUrl=NULL; LPSTR pszRootUrl=NULL; IMoniker *pMoniker=NULL; IPersistMoniker *pPersist=NULL; LPACTIVEURL pActiveUrl=NULL; BOOL fAsync=FALSE; WEBPAGEOPTIONS Options={0}; // Invalid Arg if (NULL == pmkOriginal || NULL == ppvObject || NULL == ppmkNew) return TrapError(E_INVALIDARG); // Init *ppmkNew = NULL; *ppvObject = NULL; // Thread Safety EnterCriticalSection(&m_cs); // Get the Url from the Moniker CHECKHR(hr = pmkOriginal->GetDisplayName(NULL, NULL, &pwszUrl)); // Convert to ANSI CHECKALLOC(pszUrl = PszToANSI(CP_ACP, pwszUrl)); // Unescape inplace CHECKHR(hr = UrlUnescapeA(pszUrl, NULL, NULL, URL_UNESCAPE_INPLACE)); // Raid-2508: Comment tag ( ) doesn't work in mhtml if (StrCmpNI(pszUrl, c_szMHTMLColon, lstrlen(c_szMHTMLColon)) != 0) { // Fixup ReplaceChars(pszUrl, '!', '_'); } // Free pwszUrl SafeMemFree(pwszUrl); // This will fail if pszUrl is not an mhtml: url, if it succeeds it gives me the part Url if (SUCCEEDED(MimeOleParseMhtmlUrl(pszUrl, &pszRootUrl, NULL))) { // _HandlePragmaNoCache _HandlePragmaNoCache(bindf, pszRootUrl); // See if pszUrl - mhtml: is an active Url if (FAILED(_ResolveUrl(pszRootUrl, &pActiveUrl))) { // Register an ActiveUrl CHECKHR(hr = _RegisterUrl(NULL, bindf, &pActiveUrl)); // Convert pszRootUrl to a wide CHECKALLOC(pwszUrl = PszToUnicode(CP_ACP, pszRootUrl)); // Create an Actual Url Moniker CHECKHR(hr = CreateURLMoniker(NULL, pwszUrl, &pMoniker)); // Get an IPersistMoniker CHECKHR(hr = pActiveUrl->BindToObject(IID_IPersistMoniker, (LPVOID *)&pPersist)); // Load the message with pmkOriginal hr = pPersist->Load(FALSE, pMoniker, NULL, 0); if (FAILED(hr) && E_PENDING != hr && MK_S_ASYNCHRONOUS != hr) { hr = TrapError(hr); goto exit; } // Otheriwse, good hr = S_OK; } // Return pmkOriginal (*ppmkNew) = pmkOriginal; (*ppmkNew)->AddRef(); // QI for the requested object iid CHECKHR(hr = pActiveUrl->BindToObject(riid, ppvObject)); } // Otherwise Simply see if this Url is Active else { // _HandlePragmaNoCache _HandlePragmaNoCache(bindf, pszUrl); // Try to resolve this url if (FAILED(_ResolveUrl(pszUrl, &pActiveUrl))) { // Register an ActiveUrl CHECKHR(hr = _RegisterUrl(NULL, bindf, &pActiveUrl)); // Get an IPersistMoniker CHECKHR(hr = pActiveUrl->BindToObject(IID_IPersistMoniker, (LPVOID *)&pPersist)); // Load the message with pmkOriginal hr = pPersist->Load(FALSE, pmkOriginal, pBindCtx, 0); if (FAILED(hr) && E_PENDING != hr && MK_S_ASYNCHRONOUS != hr) { hr = TrapError(hr); goto exit; } // Otheriwse, good hr = S_OK; } // Setup WebPage Options Options.cbSize = sizeof(WEBPAGEOPTIONS); Options.dwFlags = WPF_NOMETACHARSET | WPF_HTML | WPF_AUTOINLINE; // Create the root moniker CHECKHR(hr = pActiveUrl->CreateWebPage(NULL, &Options, 0, ppmkNew)); // QI for the requested object iid CHECKHR(hr = pActiveUrl->BindToObject(riid, ppvObject)); // Don't Keep Alive, assume ppvObject controls the lifetime, not pActiveUrl pActiveUrl->DontKeepAlive(); } exit: // Cleanup SafeRelease(pPersist); SafeRelease(pMoniker); SafeMemFree(pszRootUrl); SafeMemFree(pszUrl); SafeMemFree(pwszUrl); // Thread Safety LeaveCriticalSection(&m_cs); // Failed, return hr, otherwise, return MK_S_ASYNCHRONOUS if going async return hr; } // -------------------------------------------------------------------------------- // CMimeActiveUrlCache::ActiveObjectFromUrl - Called from CActiveUrlRequest::Start // -------------------------------------------------------------------------------- HRESULT CMimeActiveUrlCache::ActiveObjectFromUrl( /* in */ LPCSTR pszRootUrl, /* in */ BOOL fCreate, /* in */ REFIID riid, /* out */ LPVOID *ppvObject, /* out */ IUnknown **ppUnkKeepAlive) { // Locals HRESULT hr=S_OK; LPWSTR pwszUrl=NULL; LPACTIVEURL pActiveUrl; IMoniker *pMoniker=NULL; IPersistMoniker *pPersist=NULL; // Invalid Arg if (NULL == pszRootUrl || NULL == ppvObject || (TRUE == fCreate && NULL == ppUnkKeepAlive)) return TrapError(E_INVALIDARG); // Better not start with mhtml: Assert(StrCmpNI(pszRootUrl, "mhtml:", 6) != 0); // Thread Safety EnterCriticalSection(&m_cs); // Try to resolve this url if (FAILED(_ResolveUrl(pszRootUrl, &pActiveUrl))) { // NoCreate ? if (FALSE == fCreate) { hr = TrapError(MIME_E_NOT_FOUND); goto exit; } // Register an ActiveUrl CHECKHR(hr = _RegisterUrl(NULL, (BINDF)0, &pActiveUrl)); // Convert pszRootUrl to a wide CHECKALLOC(pwszUrl = PszToUnicode(CP_ACP, pszRootUrl)); // Create an Actual Url Moniker CHECKHR(hr = CreateURLMoniker(NULL, pwszUrl, &pMoniker)); // Get an IPersistMoniker CHECKHR(hr = pActiveUrl->BindToObject(IID_IPersistMoniker, (LPVOID *)&pPersist)); // Load the message with pmkOriginal hr = pPersist->Load(FALSE, pMoniker, NULL, 0); if (FAILED(hr) && E_PENDING != hr && MK_S_ASYNCHRONOUS != hr) { hr = TrapError(hr); goto exit; } // Return the IUnknown Keep Alive Object CHECKHR(hr = pActiveUrl->BindToObject(IID_IUnknown, (LPVOID *)ppUnkKeepAlive)); // Don't Keep Alive, assume ppvObject controls the lifetime, not pActiveUrl pActiveUrl->DontKeepAlive(); } // Return an Interface CHECKHR(hr = pActiveUrl->BindToObject(riid, ppvObject)); exit: // Cleanup SafeMemFree(pwszUrl); SafeRelease(pMoniker); SafeRelease(pPersist); // Thread Safety LeaveCriticalSection(&m_cs); // Done return hr; } // -------------------------------------------------------------------------------- // CMimeActiveUrlCache::RegisterActiveObject // -------------------------------------------------------------------------------- HRESULT CMimeActiveUrlCache::RegisterActiveObject( /* in */ LPCSTR pszRootUrl, /* in */ LPMESSAGETREE pTree) { // Locals HRESULT hr=S_OK; LPCSTR pszUrl; LPACTIVEURL pActiveUrl; // Invalid Arg if (NULL == pszRootUrl || NULL == pTree) return TrapError(E_INVALIDARG); // Thread Safety EnterCriticalSection(&m_cs); // Better start with mhtml: Assert(StrCmpNI(pszRootUrl, "mhtml:", 6) == 0); // Fixup pszUrl pszUrl = (pszRootUrl + 6); // Better not already be running if (SUCCEEDED(_ResolveUrl(pszUrl, &pActiveUrl))) { hr = TrapError(E_FAIL); goto exit; } // Register an ActiveUrl CHECKHR(hr = _RegisterUrl(pTree, (BINDF)0, &pActiveUrl)); exit: // Thread Safety LeaveCriticalSection(&m_cs); // Done return hr; }