////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 1999--2001 Microsoft Corporation // // Module Name: // CAlertEmailConsumer.cpp // // Description: // Implementation of CAlertEmailConsumer class methods // // [Header File:] // CAlertEmailConsumer.h // // History: // Xing Jin (i-xingj) 23-Dec-2000 // ////////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include #include #include #include #include #include #include #include #include "alertemailmsg.h" #include "CAlertEmailConsumer.h" // // Name of WBEM class // const WCHAR PROPERTY_CLASS_NAME [] = L"__CLASS"; // // Key name of alert email's settings. // const WCHAR SA_ALERTEMAIL_KEYPATH [] = L"SOFTWARE\\Microsoft\\ServerAppliance\\AlertEmail"; // // Delimiter // const WCHAR DELIMITER[] = L"\\"; const WCHAR ENTER[] = L"\n"; const WCHAR COLON = L':'; const WCHAR ENDCODE = L'\0'; // // HTTP header // const WCHAR HTTPHEADER[] = L"http://"; // // SMTP Meta path // const WCHAR SMTP_META_PATH[] = L"IIS://LOCALHOST/SMTPSVC/1"; // // Value name of alert email's settings. // const WCHAR ENABLEALERTEAMIL[] = L"EnableAlertEmail"; const WCHAR SENDEMAILTYPE[] = L"SendEmailType"; const WCHAR RECEIVEREMAILADDRESS[] = L"ReceiverEmailAddress"; // // The setting value of alert->email disabled. // const DWORD ALERTEMAILDISABLED = 0; // // Name of caption ID in alertdefinitions. // const WCHAR ALERTDEFINITIONCAPTIONID [] = L"CaptionRID"; // // Name of description ID in alertdefinitions. // const WCHAR ALERTDEFINITIONDESCRIPTIONRID [] = L"DescriptionRID"; // // Name of resource file in alertdefintions. // const WCHAR ALERTDEFINITIONSOURCE [] = L"Source"; // // Name of alert email resource // const WCHAR ALERTEMAILRESOURCE[] = L"AlertEmailMsg.dll"; // // Max value of Appliance Name // const DWORD MAXAPPLIANCEDNSNAME = 1024; // // WBEM namespace to connection to // const WCHAR DEFAULT_NAMESPACE[] = L"root\\MicrosoftIISv1"; // // Query Language to use for WBEM // const WCHAR QUERY_LANGUAGE [] = L"WQL"; // // WBEM query which specifies the IIS server settings we're interest in. // const WCHAR QUERY_STRING [] = L"select * from IIS_WebServerSetting where servercomment=\"Administration\""; const WCHAR SERVERBINDINGSPROP[] = L"ServerBindings"; // // PROGID of the Element Manager // const WCHAR ELEMENT_RETRIEVER [] = L"Elementmgr.ElementRetriever"; // // PROGID of the Localization Manager // const WCHAR LOCALIZATION_MANAGER [] = L"ServerAppliance.LocalizationManager"; // // Type name of alert resource information. // const WCHAR ALERTDEFINITIONS [] = L"AlertDefinitions"; ////////////////////////////////////////////////////////////////////////////// // // CAlertEmailConsumer::CAlertEmailConsumer // // Description: // Class constructor. // // History: // Xing Jin (i-xingj) 23-Dec-2000 // ////////////////////////////////////////////////////////////////////////////// CAlertEmailConsumer::CAlertEmailConsumer() { m_cRef = 0L; m_lCurAlertType = 0; m_lAlertEmailDisabled = ALERTEMAILDISABLED; m_pLocInfo = NULL; m_pcdoIMessage = NULL; m_pElementEnum = NULL; m_hAlertKey = NULL; m_hThread = NULL; m_hCloseThreadEvent = NULL; m_pstrFullyQualifiedDomainName = NULL; m_pstrNetBIOSName = NULL; } ////////////////////////////////////////////////////////////////////////////// // // CAlertEmailConsumer::~CAlertEmailConsumer // // Description: // Class deconstructor. // // History: // Xing Jin (i-xingj) 23-Dec-2000 // ////////////////////////////////////////////////////////////////////////////// CAlertEmailConsumer::~CAlertEmailConsumer() { if( m_hAlertKey != NULL ) { ::RegCloseKey( m_hAlertKey ); } if( m_pLocInfo != NULL ) { m_pLocInfo->Release(); } if( m_pElementEnum != NULL ) { m_pElementEnum->Release(); } if( m_pcdoIMessage != NULL ) { m_pcdoIMessage->Release(); } if( m_pstrFullyQualifiedDomainName != NULL ) { ::free( m_pstrFullyQualifiedDomainName ); } if( m_pstrNetBIOSName != NULL ) { ::free( m_pstrNetBIOSName ); } if( m_hThread != NULL ) { ::CloseHandle( m_hThread ); } if( m_hCloseThreadEvent != NULL ) { ::CloseHandle( m_hCloseThreadEvent ); } } ////////////////////////////////////////////////////////////////////////////// // // CAlertEmailConsumer::QueryInterface // // Description: // An method implement of IUnkown interface. // // Arguments: // [in] riid Identifier of the requested interface // [out] ppv Address of output variable that receives the // interface pointer requested in iid // // Returns: // NOERROR if the interface is supported // E_NOINTERFACE if not // // History: // Xing Jin (i-xingj) 23-Dec-2000 // ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CAlertEmailConsumer::QueryInterface( IN REFIID riid, OUT LPVOID FAR *ppv ) { *ppv=NULL; if (riid == IID_IUnknown || riid == IID_IWbemUnboundObjectSink) { *ppv = (IWbemUnboundObjectSink *) this; AddRef(); return NOERROR; } return E_NOINTERFACE; } ////////////////////////////////////////////////////////////////////////////// // // CAlertEmailConsumer::AddRef // // Description: // increments the reference count for an interface on an object // // Returns: // The new reference count. // // History: // Xing Jin (i-xingj) 23-Dec-2000 // ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP_(ULONG) CAlertEmailConsumer::AddRef(void) { InterlockedIncrement( &m_cRef ); return m_cRef; } ////////////////////////////////////////////////////////////////////////////// // // CAlertEmailConsumer::Release // // Description: // decrements the reference count for an interface on an object. // // Returns: // The new reference count. // // History: // Xing Jin (i-xingj) 23-Dec-2000 // ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP_(ULONG) CAlertEmailConsumer::Release(void) { InterlockedDecrement( &m_cRef ); if (0 != m_cRef) { return m_cRef; } // delete this; BOOL bReturn; bReturn = ::SetEvent( m_hCloseThreadEvent ); if( !bReturn ) { SATraceString( "AlertEmail:Release setevent error!!!" ); } return 0; } ////////////////////////////////////////////////////////////////////////////// // // CAlertEmailConsumer::IndicateToConsumer // // Description: // An method implement of IWbemUnboundObjectSink interface. // // Arguments: // [in] pLogicalConsumer Pointer to the logical consumer object for // which this set of objects is delivered. // [in] lObjectCount Number of objects delivered in the array that // follows. // [in] ppObjArray Pointer to an array of IWbemClassObject // instances which represent the events delivered. // // Returns: // WBEM_S_NO_ERROR if successful // WBEM_E_FAILED if not // // History: // Xing Jin (i-xingj) 23-Dec-2000 // ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CAlertEmailConsumer::IndicateToConsumer( IN IWbemClassObject *pLogicalConsumer, IN long lObjectCount, IN IWbemClassObject **ppObjArray ) { HRESULT hr = WBEM_S_NO_ERROR; if( m_lAlertEmailDisabled == ALERTEMAILDISABLED ) { return WBEM_S_NO_ERROR; } try { for (LONG lCount = 0; lCount < lObjectCount; lCount++) { // // get the event type // CComVariant vtName; hr = ppObjArray[lCount]->Get ( PROPERTY_CLASS_NAME, 0, //reserved &vtName, NULL, // type NULL // flavor ); if (FAILED (hr)) { SATraceString( "AlertEmail: IndicateToConsumer Get Class name failed" ); break; } // // check if we support the event received // if (0 == _wcsicmp (CLASS_WBEM_RAISE_ALERT, V_BSTR (&vtName))) { // // handle a raise alert event // hr = RaiseAlert ( ppObjArray[lCount] ); if ( FAILED (hr) ) { SATraceString( "AlertEmail: IndicateToConsumer RaiseAlert failed" ); break; } } else if (0 == _wcsicmp (CLASS_WBEM_CLEAR_ALERT, V_BSTR (&vtName))) { // // handle a clear alert // hr = ClearAlert ( ppObjArray[lCount] ); if ( FAILED (hr) ) { SATraceString( "AlertEmail: IndicateToConsumer ClearAlert failed" ); break; } } } // for loop } catch (...) { hr = WBEM_E_FAILED; } return hr; } ////////////////////////////////////////////////////////////////////////////// // // CAlertEmailConsumer::ClearAlert // // Description: // This is the CAlertEmailConsumer class private method // which is NOT used now. // // Arguments: // [in] pObject Pointer to an IWbemClassObject instances which // represent ClearAlert events delivered. // // Returns: // WBEM_S_NO_ERROR if successful // WBEM_E_FAILED if not // // History: // Xing Jin (i-xingj) 23-Dec-2000 // ////////////////////////////////////////////////////////////////////////////// HRESULT CAlertEmailConsumer::ClearAlert( IN IWbemClassObject *pObject ) { HRESULT hr = WBEM_S_NO_ERROR; return hr; } ////////////////////////////////////////////////////////////////////////////// // // CAlertEmailConsumer::RaiseAlert // // Description: // This is the CAlertEmailConsumer class private method // which is used to send email with the alert information // by local SMTP server. // // Arguments: // [in] pObject Pointer to an IWbemClassObject instances which // represent RaiseAlert events delivered. // // Returns: // WBEM_S_NO_ERROR if successful // WBEM_E_FAILED if not // // History: // Xing Jin (i-xingj) 23-Dec-2000 // ////////////////////////////////////////////////////////////////////////////// HRESULT CAlertEmailConsumer::RaiseAlert( IN IWbemClassObject *pObject ) { LONG lAlertType; CComVariant vtProperty; HRESULT hr = WBEM_S_NO_ERROR; // // Get alert type. // hr = pObject->Get ( PROPERTY_ALERT_TYPE, 0, //reserved &vtProperty, NULL, // type NULL // flavor ); if( FAILED (hr) ) { SATraceString( "AlertEmail:RaiseAlert get alert type failed" ); return hr; } // // Map to bitmap type definition // lAlertType = 1 << V_I4( &vtProperty ); if( lAlertType & m_lCurAlertType ) { // // It's the type user set to send mail. // do { // // Get name of alert resource dll. // CComVariant vtAlertLog; hr = pObject->Get ( PROPERTY_ALERT_LOG, 0, //reserved &vtAlertLog, NULL, // type NULL // flavor ); if( FAILED (hr) ) { SATraceString( "AlertEmail:RaiseAlert get alert source failed" ); break; } // // Get alert ID. // CComVariant vtAlertID; hr = pObject->Get ( PROPERTY_ALERT_ID, 0, //reserved &vtAlertID, NULL, // type NULL // flavor ); if( FAILED (hr) ) { SATraceString( "AlertEmail:RaiseAlert get alert ID failed" ); break; } // // Get replace strings. // CComVariant vtReplaceStr; hr = pObject->Get ( PROPERTY_ALERT_STRINGS, 0, //reserved &vtReplaceStr, NULL, // type NULL // flavor ); if( FAILED (hr) ) { SATraceString( "AlertEmail:RaiseAlert get alert replace string failed" ); break; } // // We got all neccessary info,it's time to send email. // hr = SendMailFromResource( V_BSTR( &vtAlertLog ), V_I4( &vtAlertID ), &vtReplaceStr ); if( FAILED (hr) ) { SATraceString( "AlertEmail:RaiseAlert call SendMailFromResource failed" ); break; } } //do while ( FALSE ); } // if( lAlertType & m_lCurAlertType ) return hr; } ////////////////////////////////////////////////////////////////////////////// // // CAlertEmailConsumer::SendMailFromResource // // Description: // This is the CAlertEmailConsumer class private method which is used // to get useful message about the alert from Local Manager and send // mail with the messages. // // Arguments: // [in] lpszSource Point to the name of alert resource. // [in] lSourceID Alert ID. // [in] pvtReplaceStr Point to array of replace strings. // // Returns: // WBEM_S_NO_ERROR if successful // WBEM_E_FAILED if not // // History: // Xing Jin (i-xingj) 23-Dec-2000 // ////////////////////////////////////////////////////////////////////////////// HRESULT CAlertEmailConsumer::SendMailFromResource( LPWSTR lpszSource, LONG lSourceID, VARIANT* pvtReplaceStr ) { HRESULT hr = WBEM_S_NO_ERROR; WCHAR wstrAlertItem[MAX_PATH]; IWebElement* pWebElement; IDispatch* pDispatch; // // Format the alert item name: // Name = AlertDefinitions // ::wsprintf( wstrAlertItem, L"AlertDefinitions%s%lX", lpszSource,lSourceID ); //int cchWritten = _snwprintf( wstrAlertItem, MAX_PATH, L"AlertDefinitions%s%lX", // lpszSource, lSourceID ); //if ( cchWritten >= MAX_PATH || cchWritten < 0 ) //{ // return E_INVALIDARG; //} do { // // Get the element of alert definition from element manager. // hr = m_pElementEnum->Item( &CComVariant( wstrAlertItem ), &pDispatch ); if( FAILED(hr) ) { SATraceString( "AlertEmail:SendMailFromResource find alert item failed" ); break; } hr = pDispatch->QueryInterface( __uuidof (IWebElement), reinterpret_cast (&pWebElement) ); if( FAILED(hr) ) { SATraceString( "AlertEmail:SendMailFromResource queryinterface failed" ); break; } // // allocate BSTR for alertdefintion source // CComBSTR bstrAlertDefinitionSourceName (ALERTDEFINITIONSOURCE); if (NULL == bstrAlertDefinitionSourceName.m_str) { SATraceString ("AlertEmail::SendMailFromResouce failed on SysAllocString (ALERTDEFINTIONSOURCE)"); hr = E_OUTOFMEMORY; break; } // //Get name of alert's resource dll. // AlertLog != AlertSource now! -- 2001/02/07 i-xingj // CComVariant vtAlertSource; hr = pWebElement->GetProperty ( bstrAlertDefinitionSourceName, &vtAlertSource ); if( FAILED(hr) ) { SATraceString( "AlertEmail:SendMailFromResource get Alert source failed" ); break; } // // allocate BSTR for DesinitionCaptionID string // CComBSTR bstrAlertDefinitionCaptionIDName (ALERTDEFINITIONCAPTIONID); if (NULL == bstrAlertDefinitionCaptionIDName.m_str) { SATraceString ("AlertEmail::SendMailFromResouce failed on SysAllocString (ALERTDEFINTIONCAPTIONID)"); hr = E_OUTOFMEMORY; break; } // // Get caption ID string // CComVariant vtCaptionID; hr = pWebElement->GetProperty ( bstrAlertDefinitionCaptionIDName, &vtCaptionID ); if( FAILED(hr) ) { SATraceString( "AlertEmail:SendMailFromResource find alert captionID failed" ); break; } // // allocate BSTR for AlertDescription RID // CComBSTR bstrAlertDefinitionDescriptionRIDName (ALERTDEFINITIONDESCRIPTIONRID); if (NULL == bstrAlertDefinitionDescriptionRIDName.m_str) { SATraceString ("AlertEmail::SendMailFromResouce failed on SysAllocString (ALERTDEFINITIONDESCRIPTIONRID)"); hr = E_OUTOFMEMORY; break; } // // Get description ID string // CComVariant vtDescriptionID; hr = pWebElement->GetProperty ( bstrAlertDefinitionDescriptionRIDName, &vtDescriptionID ); if( FAILED(hr) ) { SATraceString( "AlertEmail:SendMailFromResource get alert descriptionID failed" ); break; } LONG lAlertCaptionID; LONG lAlertDescriptionID; // // Change type from string to long. // if ( EOF == ::swscanf( V_BSTR( &vtCaptionID ), L"%X", &lAlertCaptionID )) { SATraceString( "AlertEmail:SendMailFromResource get caption invalid" ); break; } if ( EOF == ::swscanf( V_BSTR( &vtDescriptionID ), L"%X", &lAlertDescriptionID )) { SATraceString( "AlertEmail:SendMailFromResource get description invalid" ); break; } // // Get caption string from resource as email's subject. // CComBSTR pszSubject; hr = m_pLocInfo->GetString( V_BSTR( &vtAlertSource ), lAlertCaptionID, pvtReplaceStr, &pszSubject ); if( FAILED(hr) ) { SATraceString( "AlertEmail:SendMailFromResource get subjuct failed" ); break; } // // Get description string from resource as email's message. // CComBSTR pszMessage; hr = m_pLocInfo->GetString( V_BSTR( &vtAlertSource ), lAlertDescriptionID, pvtReplaceStr, &pszMessage ); if( FAILED(hr) ) { SATraceString( "AlertEmail:SendMailFromResource get message failed" ); break; } // // allocate BSTR for email source // CComBSTR bstrAlertEmailResourceName (ALERTEMAILRESOURCE); if (NULL == bstrAlertEmailResourceName.m_str) { SATraceString ("AlertEmail::SendMailFromResouce failed on SysAllocString (ALERTEMAILRESOURCE)"); hr = E_OUTOFMEMORY; break; } // // Get alert email defined message. // CComBSTR pszConstantMessage; hr = m_pLocInfo->GetString( bstrAlertEmailResourceName, SA_ALERTEMAIL_SETTINGS_EMAIL_CONTENT, NULL, &pszConstantMessage ); if( FAILED(hr) ) { SATraceString( "AlertEmail:SendMailFromResource get constantMsg failed" ); break; } pszMessage += CComBSTR( ENTER ); pszMessage += CComBSTR( ENTER ); pszMessage += pszConstantMessage; // // Send mail use local SMTP server. // hr = SendMail( pszSubject, pszMessage ); } //do while( FALSE ); return hr; } ////////////////////////////////////////////////////////////////////////////// // // CAlertEmailConsumer::Initialize // // Description: // This is the CAlertEmailConsumer class public method call by // CAlertEmailConsumerProvider to initialize useful parameters. // // Returns: // S_OK if successful // E_FAIL if not // // History: // Xing Jin (i-xingj) 23-Dec-2000 // ////////////////////////////////////////////////////////////////////////////// HRESULT CAlertEmailConsumer::Initialize() { ULONG ulReturn; HRESULT hr = S_OK; DWORD dwThreadID; // // Initialize Element Manager. // hr = InitializeElementManager(); if (FAILED (hr)) { SATraceString( "AlertEmailProvider:Initialize InitializeElementManager failed" ); return WBEM_E_FAILED; } // // Initialize Local Manager // hr = InitializeLocalManager(); if (FAILED (hr)) { SATraceString( "AlertEmailProvider:Initialize InitializeLocalManager failed" ); return WBEM_E_FAILED; } // // Initialize a CDO IMessage interface. // hr = InitializeCDOMessage(); if (FAILED (hr)) { SATraceString( "AlertEmailProvider:Initialize InitializeCDOMessage failed" ); return WBEM_E_FAILED; } // // Open registry key of alertemail settings. // ulReturn = ::RegOpenKey( HKEY_LOCAL_MACHINE, SA_ALERTEMAIL_KEYPATH, &m_hAlertKey ); if( ulReturn != ERROR_SUCCESS ) { SATraceString( "AlertEmail:Initialize OpenKey failed" ); return E_FAIL; } // // Get alert email settings from registry. // if( FALSE == RetrieveRegInfo() ) { SATraceString( "AlertEmail:Initialize RetrieveRegInfo failed" ); return E_FAIL; } // // Get server name fully qualified domain anem. // if( FALSE == GetComputerName( &m_pstrFullyQualifiedDomainName, ComputerNameDnsFullyQualified ) ) { SATraceString( "AlertEmail:Initialize GetComputerName ComputerNameDnsFullyQualified failed" ); return E_FAIL; } // // Get server name. // if( FALSE == GetComputerName( &m_pstrNetBIOSName, ComputerNameNetBIOS ) ) { SATraceString( "AlertEmail:Initialize GetComputerName ComputerNameNetBIOS failed" ); return E_FAIL; } // // Event for notify thread exit. // m_hCloseThreadEvent = ::CreateEvent( NULL, TRUE, FALSE, NULL ); if( m_hCloseThreadEvent == NULL ) { SATraceString( "AlertEmail:Initialize CreateEvent failed" ); return E_FAIL; } // // Thread used to monitor registy change. // m_hThread = ::CreateThread( 0, 0, CAlertEmailConsumer::RegThreadProc, this, 0, &dwThreadID ); if( m_hThread == NULL ) { SATraceString( "AlertEmail:Initialize CreateThread failed" ); return E_FAIL; } return hr; } ////////////////////////////////////////////////////////////////////////////// // // CAlertEmailConsumer::GetSMTPFromDomainName // // Description: // Get the value of "Full Qualified Domain Name" entry in SMTP Delivery tab in MMC. // // Arguments: // [out] bstrDomainName returns domain name that is found in Metabase. // // Returns: // hr // // ////////////////////////////////////////////////////////////////////////////// HRESULT CAlertEmailConsumer::GetSMTPFromDomainName( BSTR* bstrDomainName ) { HRESULT hr = S_OK; CComPtr pADs; // // Initialize for return // *bstrDomainName = NULL; CComBSTR bstrADSPath( SMTP_META_PATH ); if (NULL == bstrADSPath.m_str) { SATraceString ("CAlertEmailConsumer::GetSMTPFromDomainName failed to allocate memory for bstrADsPath"); return (E_OUTOFMEMORY); } hr = ADsGetObject( bstrADSPath, IID_IADs, (void**) &pADs ); if ( SUCCEEDED(hr) ) { CComVariant varValue; CComBSTR bstrFullyQualifiedDomainName (L"FullyQualifiedDomainName" ); if (NULL == bstrFullyQualifiedDomainName.m_str) { SATraceString ("CAlertEmailConsumer::GetSMTPFromDomainName failed to allocate memory for bstrFullyQualifiedDomainName"); hr = E_OUTOFMEMORY; } else { // Getting the FullyQualifiedDomainName property hr = pADs->Get(bstrFullyQualifiedDomainName, &varValue ); if ( SUCCEEDED(hr) ) { *bstrDomainName = SysAllocString( V_BSTR( &varValue ) ); } } } return hr; } ////////////////////////////////////////////////////////////////////////////// // // CAlertEmailConsumer::SendMail // // Description: // This is the CAlertEmailConsumer class private method which is used // to send mail through local SMTP server. // // Arguments: // [in] bstrSubject Subject string. // [in] bstrMessage Message string. // // Returns: // WBEM_S_NO_ERROR if successful // WBEM_E_FAILED if not // // History: // Xing Jin (i-xingj) 23-Dec-2000 // ////////////////////////////////////////////////////////////////////////////// HRESULT CAlertEmailConsumer::SendMail( BSTR bstrSubject, BSTR bstrMessage ) { HRESULT hr = WBEM_S_NO_ERROR; WCHAR* pstrPort = NULL; do { // // The algorithm is // Look at the value of "Full Qualified Domain Name" entry in SMTP Delivery tab in MMC. // 1) If the value is empty then the e-mail From Address is same as fully qualified domain name // 2) IF there is value and that value is different from Full Qualified Computer Name then use // 3) the following as From address. // 4) Use the From Address as appliance_name@"Full Qualified Domain Name" // // // // allocate memory for BSTR // CComBSTR bstrFullyQualifiedDomainName( m_pstrFullyQualifiedDomainName ); if (NULL == bstrFullyQualifiedDomainName.m_str) { SATraceString("AlertEmail:SendMail failed to allocate memory for bstrFullyQualifiedDomainName" ); hr = E_OUTOFMEMORY; break; } CComBSTR bstrFromAddress( m_pstrNetBIOSName ); if (NULL == bstrFromAddress.m_str) { SATraceString("AlertEmail:SendMail failed to allocate memory for bstrFromAddress" ); hr = E_OUTOFMEMORY; break; } BSTR bstrDomainName = NULL; // // Read SMTP "Full Qualified Domain Name" from Metabase hr = GetSMTPFromDomainName( &bstrDomainName ); if ( FAILED(hr) ) { SATraceString( "AlertEmail:SendMail GetSMTPFromDomainName failed" ); return E_FAIL; } if ( bstrDomainName ) { if ( _wcsicmp( bstrFullyQualifiedDomainName, bstrDomainName ) != 0 ) { bstrFromAddress += CComBSTR( L"@" ); bstrFromAddress += bstrDomainName ; } } // // Set bstrFromAddress that is formed using the above algorithm // as mail sender. // hr = m_pcdoIMessage->put_From( bstrFromAddress ); // // Free BSTR // if ( bstrDomainName ) { SysFreeString( bstrDomainName ); } CComBSTR bstrMailAddress (m_pstrMailAddress ); if (NULL == bstrMailAddress.m_str) { SATraceString("AlertEmail:SendMail failed to allocate memory for bstrMailAddress" ); hr = E_OUTOFMEMORY; break; } // // Set mail address. // hr = m_pcdoIMessage->put_To( bstrMailAddress); if( FAILED(hr) ) { SATraceString( "AlertEmail:SendMail put_To failed" ); break; } // // Set mail subject. // hr = m_pcdoIMessage->put_Subject( bstrSubject ); if( FAILED(hr) ) { SATraceString( "AlertEmail:SendMail put_Subject failed" ); break; } // // Get text bodypart from the message object. // CComPtr pMsgBodyPart; hr = m_pcdoIMessage->get_BodyPart( &pMsgBodyPart ); if( FAILED(hr) ) { SATraceString( "AlertEmail:SendMail get_TextBodyPart failed" ); break; } // // Get current char set from localize manager. // CComBSTR bstrCharSet; hr = m_pLocInfo->get_CurrentCharSet( &bstrCharSet ); if( FAILED(hr) ) { SATraceString( "AlertEmail:SendMail get_CurrentCharSet failed" ); break; } // // Set char set to text bodypart with current char set. // // TMARSH: Hardcode charset to UTF-8. hr = pMsgBodyPart->put_Charset( CComBSTR(L"utf-8") ); // hr = pMsgBodyPart->put_Charset( bstrCharSet ); if( FAILED(hr) ) { SATraceString( "AlertEmail:SendMail put_CharSet failed" ); break; } CComBSTR bstrExtendMessage; bstrExtendMessage.AppendBSTR( bstrMessage ); /* bstrExtendMessage += CComBSTR( ENTER ); bstrExtendMessage += CComBSTR( HTTPHEADER ); bstrExtendMessage += CComBSTR( m_pstrApplianceName ); hr = GetAppliancePort( &pstrPort ); if( SUCCEEDED( hr ) ) { bstrExtendMessage += CComBSTR( pstrPort ); } else { SATraceString( "AlertEmail:SendMail GetAppliancePort failed" ); } */ // // Set mail message. // hr = m_pcdoIMessage->put_TextBody( bstrExtendMessage ); if( FAILED(hr) ) { SATraceString( "AlertEmail:SendMail put_TextBody failed" ); break; } // // Send it. // hr = m_pcdoIMessage->Send(); }while( FALSE ); if( pstrPort!= NULL ) { ::free( pstrPort ); } return hr; } ////////////////////////////////////////////////////////////////////////////// // // CAlertEmailConsumer::GetFullyQualifiedDomainName // // Description: // This is the CAlertEmailConsumer class private method which is used // to get local appliance name in DNS format. // // Arguments: // [in,out] pstrComputerName Pointer of computer name string. // // Returns: // TRUE if successful // FALSE if not // // History: // Xing Jin (i-xingj) 23-Dec-2000 // ////////////////////////////////////////////////////////////////////////////// BOOL CAlertEmailConsumer::GetComputerName( LPWSTR* pstrComputerName, COMPUTER_NAME_FORMAT nametype ) { BOOL bReturn = FALSE; DWORD dwSize = 0; DWORD dwCount = 1; do { if( *pstrComputerName != NULL ) { ::free( *pstrComputerName ); } dwSize = MAXAPPLIANCEDNSNAME * dwCount; *pstrComputerName = ( LPWSTR ) ::malloc( sizeof(WCHAR) * dwSize ); if( *pstrComputerName == NULL ) { SATraceString( "AlertEmail:GetApplianceName malloc failed" ); break; } // // Get local computer name. // bReturn = ::GetComputerNameEx( nametype, *pstrComputerName, &dwSize ); dwCount <<= 1; } while( !bReturn && ERROR_MORE_DATA == ::GetLastError() && dwCount < 32 ); return bReturn; } ////////////////////////////////////////////////////////////////////////////// // // CAlertEmailConsumer::GetAppliancePort // // Description: // This is the CAlertEmailConsumer class private method which is used // to get local appliance port. // // Arguments: // [in,out] pstrPort Pointer of server port string. // // Returns: // TRUE if successful // FALSE if not // // History: // Xing Jin (i-xingj) 23-Dec-2000 // ////////////////////////////////////////////////////////////////////////////// HRESULT CAlertEmailConsumer::GetAppliancePort( LPWSTR* pstrPort ) { HRESULT hr = S_OK; try { do { CComPtr pWbemLocator; CComPtr pWbemServices; CComPtr pEnumServices; // // create the WBEM locator object // hr = ::CoCreateInstance ( CLSID_WbemLocator, 0, //aggregation pointer CLSCTX_INPROC_SERVER, IID_IWbemLocator, (PVOID*) &pWbemLocator ); if( FAILED(hr) ) { SATraceString( "AlertEmail:GetAppliancePort CoCreateInstance failed" ); break; } // // allocate memory for BSTR // CComBSTR bstrDefaultNameSpace (DEFAULT_NAMESPACE); if (NULL == bstrDefaultNameSpace.m_str) { SATraceString("AlertEmail:GetAppliancePort failed to allocate memory for DEFAULT_NAMESPACE" ); hr = E_OUTOFMEMORY; break; } // // connect to WMI // hr = pWbemLocator->ConnectServer ( bstrDefaultNameSpace, NULL, //user-name NULL, //password 0, //current-locale 0, //reserved NULL, //authority NULL, //context &pWbemServices ); if( hr != WBEM_S_NO_ERROR ) { SATraceString( "AlertEmail:GetAppliancePort ConnectServer failed" ); break; } // // Query Web server instance. // hr = pWbemServices->ExecQuery( CComBSTR( QUERY_LANGUAGE ), CComBSTR( QUERY_STRING ), 0, NULL, &pEnumServices ); if( hr != WBEM_S_NO_ERROR ) { SATraceString( "AlertEmail:GetAppliancePort ExecQuery failed" ); break; } CComPtr pService; ULONG uReturned; // // Now,we only care for the first match. // hr = pEnumServices->Next( WBEM_NO_WAIT, 1, &pService, &uReturned ); if( hr != WBEM_S_NO_ERROR ) { SATraceString( "AlertEmail:GetAppliancePort nothing found" ); break; } CComVariant vtServerBindings; // // Get the "ServerBindings" property. // hr = pService->Get( CComBSTR( SERVERBINDINGSPROP ), 0, &vtServerBindings, 0, 0 ); if ( FAILED(hr) || !V_ISARRAY( &vtServerBindings ) ) { hr = E_FAIL; SATraceString( "AlertEmail:GetAppliancePort get serverbindings failed" ); break; } SAFEARRAY* psa; BSTR HUGEP *pbstr; // // The property type is VT_ARRAY | VT_BSTR. // psa = V_ARRAY( &vtServerBindings ); if( psa->cDims <= 0 ) { hr = E_FAIL; SATraceString( "AlertEmail:GetAppliancePort array dim error" ); break; } // // Access array data directly,it's a faster way. // hr = ::SafeArrayAccessData( psa, ( void HUGEP** )&pbstr ); if (FAILED(hr)) { SATraceString( "AlertEmail:GetAppliancePort SafeArrayAccessData failed" ); break; } // // Now we can alloc the port string. // *pstrPort = ( LPWSTR )malloc( sizeof(WCHAR) * MAX_COMPUTERNAME_LENGTH ); if( *pstrPort == NULL ) { hr = E_FAIL; SATraceString( "AlertEmail:GetAppliancePort malloc failed" ); break; } WCHAR* pszTemp1; WCHAR* pszTemp2; pszTemp1 = ::wcschr( pbstr[0], COLON ); pszTemp2 = ::wcsrchr( pbstr[0], COLON ); if( pszTemp2 != NULL && pszTemp1 != NULL ) { pszTemp2[0] = ENDCODE; ::wcscpy( *pstrPort, pszTemp1 ); } else { SATraceString( "AlertEmail:GetAppliancePort string formate error" ); hr = E_FAIL; } ::SafeArrayUnaccessData( psa ); } while( false ); } catch (...) { SATraceString( "AlertEmail:GetAppliancePort unkown exception" ); hr = E_FAIL; } return hr; } ////////////////////////////////////////////////////////////////////////////// // // CAlertEmailConsumer::RetrieveRegInfo // // Description: // This is the CAlertEmailConsumer class private method which is used // to retrieve alert email settings from registry. // // Returns: // TRUE if successful // FALSE if not // // History: // Xing Jin (i-xingj) 23-Dec-2000 // ////////////////////////////////////////////////////////////////////////////// BOOL CAlertEmailConsumer::RetrieveRegInfo() { BOOL bReturn = TRUE; LONG lReturn; DWORD dwDataSize; // // Get the email address will be send to. // dwDataSize = sizeof(m_pstrMailAddress); lReturn = ::RegQueryValueEx( m_hAlertKey, RECEIVEREMAILADDRESS, NULL, NULL, reinterpret_cast(m_pstrMailAddress), &dwDataSize ); if( lReturn != ERROR_SUCCESS) { m_pstrMailAddress[0] = L'\0'; // RegQueryValueEx doesn't guarantee // a desirable value, so clear the string. SATraceString( "AlertEmail:RetrieveRegInfo query address failed" ); bReturn = FALSE; } else { _ASSERT(dwDataSize <= sizeof(m_pstrMailAddress)); // // Validate the e-mail address length. // LONG lLastCharacter; if( sizeof( m_pstrMailAddress[0] ) > dwDataSize ) { lLastCharacter = 0; } else { lLastCharacter = dwDataSize / sizeof( m_pstrMailAddress[0] ) - 1; } if( sizeof(m_pstrMailAddress) == dwDataSize && L'\0' != m_pstrMailAddress[lLastCharacter] ) { SATraceString( "AlertEmail:RetrieveRegInfo address too long" ); bReturn = FALSE; } m_pstrMailAddress[lLastCharacter] = L'\0'; } // // Get alert enable setting. // dwDataSize = sizeof( LONG ); lReturn = ::RegQueryValueEx( m_hAlertKey, ENABLEALERTEAMIL, NULL, NULL, reinterpret_cast(&m_lAlertEmailDisabled), &dwDataSize ); if( lReturn != ERROR_SUCCESS) { SATraceString( "AlertEmail:RetrieveRegInfo query enablealertemail failed" ); bReturn = FALSE; } // // Get alert type setting. // dwDataSize = sizeof( LONG ); lReturn = ::RegQueryValueEx( m_hAlertKey, SENDEMAILTYPE, NULL, NULL, reinterpret_cast(&m_lCurAlertType), &dwDataSize ); if( lReturn != ERROR_SUCCESS) { SATraceString( "AlertEmail:RetrieveRegInfo query enablealertemail failed" ); bReturn = FALSE; } return bReturn; } ////////////////////////////////////////////////////////////////////////////// // // CAlertEmailConsumer::RegThreadProc // // Description: // This is the CAlertEmailConsumer class static method which is used // as worker thread entry. // // Arguments: // [in] pIn Point to an instance of CAlertEmailConsumer class. // // Returns: // 0 if successful // -1 if not // // History: // Xing Jin (i-xingj) 23-Dec-2000 // ////////////////////////////////////////////////////////////////////////////// DWORD WINAPI CAlertEmailConsumer::RegThreadProc( PVOID pIn ) { // // Make transition to the per-instance method. // ( (CAlertEmailConsumer *) pIn )->RegThread(); return 0; } ////////////////////////////////////////////////////////////////////////////// // // CAlertEmailConsumer::RegThread // // Description: // This is the CAlertEmailConsumer class public method which is real // worker thread process. // // History: // Xing Jin (i-xingj) 23-Dec-2000 // ////////////////////////////////////////////////////////////////////////////// void CAlertEmailConsumer::RegThread() { HANDLE hHandleArray[2]; DWORD dwEventCount; DWORD dwReturn; SATraceString( "AlertEmail:RegThread enter" ); // // Handle list used by WaitForMultipleObjects // hHandleArray[0] = m_hCloseThreadEvent; // // Event for RegNotifyChangeKeyValue. // hHandleArray[1] = ::CreateEvent( NULL, FALSE, FALSE, NULL ); if( hHandleArray[1] != NULL ) { dwEventCount = 2; // // Monitor key change action. // ::RegNotifyChangeKeyValue( m_hAlertKey, //AlertEmail key FALSE, //No subkey REG_NOTIFY_CHANGE_LAST_SET, //Value change hHandleArray[1], //Event handle TRUE ); //APC } else { SATraceString( "AlertEmail:RegThread CreateEvent failed" ); dwEventCount = 1; } while( TRUE ) { // // Wait for both close and regchange event. // dwReturn = ::WaitForMultipleObjects( dwEventCount, hHandleArray, FALSE, INFINITE ); switch( dwReturn ) { case WAIT_OBJECT_0: { // // Close thread event set in release method. // SATraceString( "AlertEmail:RegThread get close event" ); if( hHandleArray[1] != NULL ) { ::CloseHandle( hHandleArray[1] ); } // // Clean up. // delete this; return; } //case WAIT_OBJECT_0: case WAIT_OBJECT_0 + 1: { // // Registry changed event. // SATraceString( "AlertEmail:RegThread get reg event" ); BOOL bReturn; // // Refresh alert email settings. // bReturn = RetrieveRegInfo(); if( bReturn == FALSE ) { SATraceString( "AlertEmail:RegThread RetrieveRegInfo failed" ); } break; } //case WAIT_OBJECT_0 + 1: default: { // // Wait error ocupied. // SATraceString( "AlertEmail:RegThread waitevent error" ); break; } //default: } //switch(dwReturn) } // While( TRUE ) return; } ////////////////////////////////////////////////////////////////////////////// // // CAlertEmailConsumer::InitializeLocalManager // // Description: // This is the CAlertEmailConsumer class private method which is used // to get object of Local Manager. // // Returns: // WBEM_S_NO_ERROR if successful // WBEM_E_FAILED if not // // History: // Xing Jin (i-xingj) 23-Dec-2000 // ////////////////////////////////////////////////////////////////////////////// HRESULT CAlertEmailConsumer::InitializeLocalManager() { CLSID clsidLocMgr; HRESULT hr; hr = ::CLSIDFromProgID ( LOCALIZATION_MANAGER, &clsidLocMgr ); if (SUCCEEDED (hr)) { // // create the Localization Manager COM object // hr = ::CoCreateInstance ( clsidLocMgr, NULL, CLSCTX_INPROC_SERVER, __uuidof (ISALocInfo), (PVOID*) &m_pLocInfo ); } return hr; } ////////////////////////////////////////////////////////////////////////////// // // CAlertEmailConsumer::InitializeElementManager // // Description: // This is the CAlertEmailConsumer class private method which is used // to get object of elements enum interface from Element manager. // // Returns: // WBEM_S_NO_ERROR if successful // WBEM_E_FAILED if not // // History: // Xing Jin (i-xingj) 23-Dec-2000 // ////////////////////////////////////////////////////////////////////////////// HRESULT CAlertEmailConsumer::InitializeElementManager() { HRESULT hr = WBEM_S_NO_ERROR; IDispatch *pDispatch = NULL; IWebElementRetriever *pWebElementRetriever = NULL; do { // // Get Element Manager's CLSID. // CLSID clsid; hr = ::CLSIDFromProgID ( ELEMENT_RETRIEVER, &clsid ); if (FAILED (hr)) { break; } // // create the WebElementRetriever now // hr = ::CoCreateInstance ( clsid, NULL, CLSCTX_LOCAL_SERVER, IID_IWebElementRetriever, (PVOID*) &pWebElementRetriever ); if (FAILED (hr)) { break; } // // allocate memory for BSTR(alert definitions) // CComBSTR bstrAlertDefinitions (ALERTDEFINITIONS); if (NULL == bstrAlertDefinitions.m_str) { hr = E_OUTOFMEMORY; break; } // // Initial now // hr = pWebElementRetriever->GetElements ( WEB_ELEMENT_TYPE_DEFINITION, bstrAlertDefinitions, &pDispatch ); if (FAILED (hr)) { break; } // // get the enum variant // hr = pDispatch->QueryInterface ( IID_IWebElementEnum, reinterpret_cast (&m_pElementEnum) ); }while( FALSE ); if( pDispatch != NULL ) { pDispatch->Release(); } if( pWebElementRetriever != NULL ) { pWebElementRetriever->Release(); } return hr; } ////////////////////////////////////////////////////////////////////////////// // // CAlertEmailConsumer::InitializeCDOMessage // // Description: // This is the CAlertEmailConsumer class private method which is used // to get object of CDO::IMessage and set the configuration as using // local SMTP server. // // Returns: // WBEM_S_NO_ERROR if successful // WBEM_E_FAILED if not // // History: // Xing Jin (i-xingj) 23-Dec-2000 // ////////////////////////////////////////////////////////////////////////////// HRESULT CAlertEmailConsumer::InitializeCDOMessage() { HRESULT hr = S_OK; CComPtr pConfig; do { // // Get an object of IMessage // hr = CoCreateInstance( CLSID_Message, NULL, CLSCTX_INPROC_SERVER, IID_IMessage, (PVOID*) &m_pcdoIMessage ); if (FAILED (hr)) { SATraceString( "AlertEmail: InitializeCDOMessage CoCreateInstance failed" ); break; } // // Get the configuration in this message object. // hr = m_pcdoIMessage->get_Configuration(&pConfig); if (FAILED (hr)) { SATraceString( "AlertEmail: InitializeCDOMessage get_Configuration failed" ); break; } // // Set the configuration as default setting of local // SMTP server. // hr = pConfig->Load( cdoIIS, NULL ); } while( FALSE ); return hr; }