#ifndef _CDFAGENT_H #define _CDFAGENT_H #include "msxml.h" class CProcessElement; class CProcessRoot; class CUrlTrackingCache; class CRunDeliveryAgentSink { public: // OnAgentProgress not currently called virtual HRESULT OnAgentProgress() { return E_NOTIMPL; } // OnAgentEnd called when agent is complete. fSynchronous means that StartAgent call // has not yet returned; hrResult will be returned from StartAgent virtual HRESULT OnAgentEnd(const SUBSCRIPTIONCOOKIE *pSubscriptionCookie, long lSizeDownloaded, HRESULT hrResult, LPCWSTR wszResult, BOOL fSynchronous) { return E_NOTIMPL; } }; class CProcessElementSink { public: virtual HRESULT OnChildDone(CProcessElement *pChild, HRESULT hr) = 0; virtual LPCWSTR GetBaseUrl() = 0; // Returned pointer doesn't need to get freed virtual BOOL IsGlobalLog() = 0; }; typedef struct CDF_TIME { WORD wDay; WORD wHour; WORD wMin; WORD wReserved; DWORD dwConvertedMinutes; // Day/Hour/Min in Minutes } CDF_TIME; ////////////////////////////////////////////////////////////////////////// // // Channel Agent object // ////////////////////////////////////////////////////////////////////////// class CChannelAgent : public CDeliveryAgent, public CUrlDownloadSink, public CProcessElementSink { friend CProcessElement; // for SendUpdateProgress friend CProcessRoot; // for laziness protected: // properties LPWSTR m_pwszURL; DWORD m_dwChannelFlags; // used during updating CUrlDownload *m_pCurDownload; IExtractIcon *m_pChannelIconHelper; BOOL m_fHasInitCookie; // One time deal, don't try again. VARIANT m_varChange; GROUPID m_llCacheGroupID; GROUPID m_llOldCacheGroupID; // other agent flags enum { FLAG_CDFCHANGED = 0x80000000 // did the CDF change? }; private: ~CChannelAgent(void); public: CChannelAgent(void); // CUrlDownloadSink HRESULT OnAuthenticate(HWND *phwnd, LPWSTR *ppszUsername, LPWSTR *ppszPassword); HRESULT OnDownloadComplete(UINT iID, int iError); // CProcessElementSink HRESULT OnChildDone(CProcessElement *pChild, HRESULT hr); LPCWSTR GetBaseUrl() { return GetUrl(); } BOOL IsGlobalLog() { return FALSE; } // virtual functions overriding CDeliveryAgent HRESULT AgentPause(DWORD dwFlags); HRESULT AgentResume(DWORD dwFlags); HRESULT AgentAbort(DWORD dwFlags); STDMETHODIMP GetIconLocation(UINT, LPTSTR, UINT, int *, UINT *); STDMETHODIMP Extract(LPCTSTR, UINT, HICON *, HICON *, UINT); LPCWSTR GetUrl() { return m_pwszURL; } ISubscriptionItem *GetStartItem() { return m_pSubscriptionItem; } BOOL IsChannelFlagSet(DWORD dwFlag) { return dwFlag & m_dwChannelFlags; } void SetScreenSaverURL(LPCWSTR pwszURL); protected: // CDeliveryAgent overrides HRESULT ModifyUpdateEnd(ISubscriptionItem *pEndItem, UINT *puiRes); HRESULT StartOperation(); HRESULT StartDownload(); void CleanUp(); // Used during updates CProcessRoot *m_pProcess; LPWSTR m_pwszScreenSaverURL; public: DWORD m_dwMaxSizeKB; }; ////////////////////////////////////////////////////////////////////////// // // CRunDeliveryAgent object // Will run a delivery agent and host it for you // Create, call Init, then call StartAgent // Use static function SafeRelease to safely release this class. // ////////////////////////////////////////////////////////////////////////// class CRunDeliveryAgent : public ISubscriptionAgentEvents { protected: virtual ~CRunDeliveryAgent(); CRunDeliveryAgentSink *m_pParent; ULONG m_cRef; ISubscriptionItem *m_pItem; ISubscriptionAgentControl *m_pAgent; HRESULT m_hrResult; BOOL m_fInStartAgent; CLSID m_clsidDest; void CleanUp(); public: CRunDeliveryAgent(); HRESULT Init(CRunDeliveryAgentSink *pParent, ISubscriptionItem *pItem, REFCLSID rclsidDest); void LeaveMeAlone() { m_pParent = NULL; } inline static void SafeRelease(CRunDeliveryAgent * &pThis) { if (pThis) { pThis->m_pParent=NULL; pThis->Release(); pThis=NULL; } } static HRESULT CreateNewItem(ISubscriptionItem **ppItem, REFCLSID rclsidAgent); // StartAgent will return E_PENDING if agent is running. Otherwise it will return // synchronous result code from agent. HRESULT StartAgent(); HRESULT AgentPause(DWORD dwFlags); HRESULT AgentResume(DWORD dwFlags); HRESULT AgentAbort(DWORD dwFlags); // IUnknown members STDMETHODIMP QueryInterface(REFIID riid, void **ppunk); STDMETHODIMP_(ULONG) AddRef(); STDMETHODIMP_(ULONG) Release(); // ISubscriptionAgentEvents members STDMETHODIMP UpdateBegin(const SUBSCRIPTIONCOOKIE *pSubscriptionCookie); STDMETHODIMP UpdateProgress(const SUBSCRIPTIONCOOKIE *pSubscriptionCookie, long lSizeDownloaded, long lProgressCurrent, long lProgressMax, HRESULT hrStatus, LPCWSTR wszStatus); STDMETHODIMP UpdateEnd(const SUBSCRIPTIONCOOKIE *pSubscriptionCookie, long lSizeDownloaded, HRESULT hrResult, LPCWSTR wszResult); STDMETHODIMP ReportError(const SUBSCRIPTIONCOOKIE *pSubscriptionCookie, HRESULT hrError, LPCWSTR wszError); }; class CChannelAgentHolder : public CRunDeliveryAgent, public IServiceProvider { protected: ~CChannelAgentHolder(); public: CChannelAgentHolder(CChannelAgent *pChannelAgent, CProcessElement *pProcess); // IUnknown STDMETHODIMP QueryInterface(REFIID riid, void **ppunk); STDMETHODIMP_(ULONG) AddRef(); STDMETHODIMP_(ULONG) Release(); // ServiceProvider STDMETHODIMP QueryService(REFGUID guidService, REFIID riid, void **ppvObject); protected: CChannelAgent *m_pChannelAgent; CProcessElement *m_pProcess; }; ////////////////////////////////////////////////////////////////////////// // // Process Element objects // // User of this class // 1) Creates & passes in self & element // 2) Calls Run // 3) If E_PENDING, will receive call back "OnChildDone" // // The purpose of this class is simply to allow us to save our state of // walking the XML OM, so that we can host another deliver agent // (webcrawler). This requires us to return out to the thread's message // pump after sending the "agent start" to the web crawler. // The if a webcrawl is initiated the class creates its own sink. Classes // also keep references to their spawned enumerations in case of an // abort, which comes from the root element (CProcessRoot instance) // ////////////////////////////////////////////////////////////////////////// class CProcessElement : public CProcessElementSink, public CRunDeliveryAgentSink { public: CProcessElement(CProcessElementSink *pParent, CProcessRoot *pRoot, IXMLElement *pEle); ~CProcessElement(); // From CRunDeliveryAgent HRESULT OnAgentEnd(const SUBSCRIPTIONCOOKIE *pSubscriptionCookie, long lSizeDownloaded, HRESULT hrResult, LPCWSTR wszResult, BOOL fSynchronous); typedef HRESULT (CChannelAgent::*PFNHANDLETAG)(LPCWSTR pwszTagName, IXMLElement *pEle); typedef struct { LPCWSTR pwszTagName; PFNHANDLETAG pfnHandleTag; } TAGTABLE; // E_FAIL, E_PENDING, or S_OK virtual HRESULT Run(); // Called when E_PENDING DoChild returns (from m_pCurChild) HRESULT OnChildDone(CProcessElement *pChild, HRESULT hr); HRESULT Pause(DWORD dwFlags); HRESULT Resume(DWORD dwFlags); HRESULT Abort(DWORD dwFlags); IXMLElement *GetCurrentElement() { return m_pChildElement; } protected: // Returns E_PENDING, or S_OK if enumeration complete HRESULT DoEnumeration(); // E_PENDING if webcrawl pending HRESULT DoChild(CProcessElement *pChild); // Should return E_PENDING, or S_OK if processing done // Can return E_ABORT to abort entire CDF processing virtual HRESULT ProcessItemInEnum(LPCWSTR pwszTagName, IXMLElement *pItem) = 0; // Called by DoEnumeration when it's done. Return value ignored. virtual HRESULT EnumerationComplete() { return S_OK; } // E_PENDING, or E_FAIL HRESULT DoDeliveryAgent(ISubscriptionItem *pItem, REFCLSID rclsid, LPCWSTR pwszURL=NULL); HRESULT DoWebCrawl(IXMLElement *pItem, LPCWSTR pwszURL=NULL); HRESULT DoSoftDist(IXMLElement *pItem); BOOL ShouldDownloadLogo(IXMLElement *pLogo); // If relative url, will combine with most recent base URL // *ppwszRetUrl should be NULL & will be LocalAlloced if needed HRESULT CombineWithBaseUrl(LPCWSTR pwszUrl, LPWSTR *ppwszRetUrl); // Returned pointer doesn't need to get freed LPCWSTR GetBaseUrl() { return m_pParent->GetBaseUrl(); } BOOL IsGlobalLog() { return m_pParent->IsGlobalLog(); } CProcessRoot *m_pRoot; CProcessElement *m_pCurChild; IXMLElementCollection *m_pCollection; long m_lIndex; long m_lMax; BOOL m_fStartedEnumeration; BOOL m_fSentEnumerationComplete; IXMLElement *m_pElement; IXMLElement *m_pChildElement; CProcessElementSink *m_pParent; CRunDeliveryAgent *m_pRunAgent; }; class CProcessRoot : public CProcessElement { public: CProcessRoot(CChannelAgent *pParent, IXMLElement *pRoot); ~CProcessRoot(); CChannelAgent *m_pChannelAgent; DWORD m_dwCurSizeKB; int m_iTotalStarted; BOOL m_fMaxSizeExceeded; protected: ISubscriptionItem *m_pDefaultStartItem; CUrlTrackingCache *m_pTracking; public: HRESULT CreateStartItem(ISubscriptionItem **ppItem); IUnknown *DefaultStartItem() { return m_pDefaultStartItem; } HRESULT Run(); // Called when E_PENDING DoChild returns (from m_pCurChild, a CProcessChannel) HRESULT OnChildDone(CProcessElement *pChild, HRESULT hr); HRESULT OnAgentEnd(const SUBSCRIPTIONCOOKIE *, long, HRESULT, LPCWSTR, BOOL); BOOL IsPaused() { return m_pChannelAgent->IsPaused(); } BOOL IsChannelFlagSet(DWORD dw) { return m_pChannelAgent->IsChannelFlagSet(dw); } // HRESULT ProcessLogin(IXMLElement *pElement); HRESULT DoTrackingFromItem(IXMLElement *pItem, LPCWSTR pwszUrl, BOOL fForceLog); HRESULT DoTrackingFromLog(IXMLElement *pItem); protected: HRESULT ProcessItemInEnum(LPCWSTR pwszTagName, IXMLElement *pItem); LPCWSTR GetBaseUrl() { return m_pChannelAgent->GetUrl(); } }; class CProcessChannel : public CProcessElement { public: CProcessChannel(CProcessElementSink *pParent, CProcessRoot *pRoot, IXMLElement *pItem); ~CProcessChannel(); HRESULT Run(); void SetGlobalLogFlag(BOOL flag) { m_fglobalLog = flag; } protected: HRESULT ProcessItemInEnum(LPCWSTR pwszTagName, IXMLElement *pItem); LPCWSTR GetBaseUrl() { if (m_bstrBaseUrl) return m_bstrBaseUrl; return m_pParent->GetBaseUrl(); } BOOL IsGlobalLog() { return m_fglobalLog; } HRESULT CheckPreCache(); BOOL m_fDownloadedHREF; BSTR m_bstrBaseUrl; BOOL m_fglobalLog; }; class CProcessItem : public CProcessElement { public: CProcessItem(CProcessElementSink *pParent, CProcessRoot *pRoot, IXMLElement *pItem); ~CProcessItem(); protected: HRESULT ProcessItemInEnum(LPCWSTR pwszTagName, IXMLElement *pItem); HRESULT EnumerationComplete(); BSTR m_bstrAnchorURL; BOOL m_fScreenSaver; BOOL m_fDesktop; BOOL m_fEmail; }; class CProcessSchedule : public CProcessElement { public: CProcessSchedule(CProcessElementSink *pParent, CProcessRoot *pRoot, IXMLElement *pItem); HRESULT Run(); protected: HRESULT ProcessItemInEnum(LPCWSTR pwszTagName, IXMLElement *pItem); HRESULT EnumerationComplete(); CDF_TIME m_timeInterval; CDF_TIME m_timeEarliest; CDF_TIME m_timeLatest; SYSTEMTIME m_stStartDate; SYSTEMTIME m_stEndDate; public: TASK_TRIGGER m_tt; }; class CExtractSchedule : public CProcessElement { public: CExtractSchedule(IXMLElement *pEle, CExtractSchedule *m_pExtractRoot); HRESULT ProcessItemInEnum(LPCWSTR pwszTagName, IXMLElement *pItem); HRESULT GetTaskTrigger(TASK_TRIGGER *ptt); virtual HRESULT Run(); TASK_TRIGGER m_tt; CExtractSchedule *m_pExtractRoot; protected: LPCWSTR GetBaseUrl() { return NULL; } }; #endif // _CDFAGENT_H