// expire.cpp : Implementation of CnntpadmApp and DLL registration. #include "stdafx.h" #include "nntpcmn.h" #include "expire.h" #include "oleutil.h" #include "nntptype.h" #include "nntpapi.h" #include // Must define THIS_FILE_* macros to use NntpCreateException() #define THIS_FILE_HELP_CONTEXT 0 #define THIS_FILE_PROG_ID _T("Nntpadm.Expiration.1") #define THIS_FILE_IID IID_INntpAdminExpiration ///////////////////////////////////////////////////////////////////////////// // // // Use a macro to define all the default methods // DECLARE_METHOD_IMPLEMENTATION_FOR_STANDARD_EXTENSION_INTERFACES(NntpAdminExpiration, CNntpAdminExpiration, IID_INntpAdminExpiration) STDMETHODIMP CNntpAdminExpiration::InterfaceSupportsErrorInfo(REFIID riid) { static const IID* arr[] = { &IID_INntpAdminExpiration, }; for (int i=0;i 0 ) { rgNewExpires = new CExpirationPolicy [ cExpires ]; for ( i = 0; i < cExpires; i++ ) { rgNewExpires[i].FromExpireInfo ( &pExpireInfo[i] ); if ( !rgNewExpires[i].CheckValid () ) { hr = E_OUTOFMEMORY; goto Exit; } } } m_fEnumerated = TRUE; m_rgExpires = rgNewExpires; m_cCount = cExpires; Exit: if ( FAILED(hr) ) { delete [] rgNewExpires; } if ( pExpireInfo ) { ::NetApiBufferFree ( pExpireInfo ); } TRACE_HRESULT(hr); TraceFunctLeave (); return hr; } STDMETHODIMP CNntpAdminExpiration::GetNth ( long lIndex ) { TraceFunctEnter ( "CNntpAdminExpiration::GetNth" ); HRESULT hr = NOERROR; // Did we enumerate first? if ( m_rgExpires == NULL ) { TraceFunctLeave (); return NntpCreateException ( IDS_NNTPEXCEPTION_DIDNT_ENUMERATE ); } // Is the index valid? if ( lIndex < 0 || (DWORD) lIndex >= m_cCount ) { TraceFunctLeave (); return NntpCreateException ( IDS_NNTPEXCEPTION_INVALID_INDEX ); } // // Copy the properties from m_rgExpires [ lIndex ] to member variables: // _ASSERT ( lIndex >= 0 ); _ASSERT ( (DWORD) lIndex < m_cCount ); _ASSERT ( m_rgExpires != NULL ); m_expireCurrent = m_rgExpires[ (DWORD) lIndex ]; // Check to make sure the strings were copied okay: if ( !m_expireCurrent.CheckValid() ) { return E_OUTOFMEMORY; } _ASSERT ( m_expireCurrent.CheckValid() ); // ( CComBSTR handles free-ing of old properties ) TraceFunctLeave (); return NOERROR; } STDMETHODIMP CNntpAdminExpiration::FindID ( long lID, long * plIndex ) { TraceFunctEnter ( "CNntpAdminExpiration::FindID" ); HRESULT hr = NOERROR; // Assume that we can't find it: *plIndex = IndexFromID ( lID ); TraceFunctLeave (); return hr; } STDMETHODIMP CNntpAdminExpiration::Add ( ) { TraceFunctEnter ( "CNntpAdminExpiration::Add" ); HRESULT hr = NOERROR; CExpirationPolicy * rgNewExpireArray = NULL; DWORD cNewCount = m_cCount + 1; DWORD i; hr = m_expireCurrent.Add ( m_iadsImpl.QueryComputer(), m_iadsImpl.QueryInstance() ); BAIL_ON_FAILURE(hr); // Add the new Expire to our current Expire list: _ASSERT ( IndexFromID ( m_expireCurrent.m_dwExpireId ) == (DWORD) -1 ); // Allocate the new array: _ASSERT ( cNewCount == m_cCount + 1 ); rgNewExpireArray = new CExpirationPolicy [ cNewCount ]; if ( rgNewExpireArray == NULL ) { FatalTrace ( (LPARAM) this, "Out of memory" ); hr = E_OUTOFMEMORY; goto Exit; } // Copy the old array into the new one: for ( i = 0; i < m_cCount; i++ ) { rgNewExpireArray[i] = m_rgExpires[i]; } // Add the new element: rgNewExpireArray[cNewCount - 1] = m_expireCurrent; // Check to make sure everything was allocated okay: for ( i = 0; i < cNewCount; i++ ) { if ( !rgNewExpireArray[i].CheckValid() ) { FatalTrace ( (LPARAM) this, "Out of memory" ); hr = E_OUTOFMEMORY; goto Exit; } } // Replace the old array with the new one: delete [] m_rgExpires; m_rgExpires = rgNewExpireArray; m_cCount = cNewCount; Exit: if ( FAILED(hr) ) { delete [] rgNewExpireArray; } TRACE_HRESULT(hr); TraceFunctLeave (); return hr; } STDMETHODIMP CNntpAdminExpiration::Set ( ) { TraceFunctEnter ( "CNntpAdminExpiration::Set" ); HRESULT hr = NOERROR; DWORD index; hr = m_expireCurrent.Set ( m_iadsImpl.QueryComputer(), m_iadsImpl.QueryInstance() ); if ( FAILED(hr) ) { goto Exit; } index = IndexFromID ( m_expireCurrent.m_dwExpireId ); if ( index == (DWORD) -1 ) { ErrorTraceX ( (LPARAM) this, "Couldn't find Expire with ID: %d", m_expireCurrent.m_dwExpireId ); // This is okay, since we succeeded in setting the current Expire already. goto Exit; } // Set the current Expire in the current Expire list: m_rgExpires[index] = m_expireCurrent; if ( !m_rgExpires[index].CheckValid () ) { FatalTrace ( (LPARAM) this, "Out of memory" ); hr = E_OUTOFMEMORY; goto Exit; } Exit: TRACE_HRESULT(hr); TraceFunctLeave (); return hr; } STDMETHODIMP CNntpAdminExpiration::Remove ( long lID ) { TraceFunctEnter ( "CNntpAdminExpiration::Remove" ); HRESULT hr = NOERROR; DWORD index; index = IndexFromID ( lID ); if ( index == (DWORD) -1 ) { ErrorTraceX ( (LPARAM) this, "Couldn't find Expire with ID: %d", lID ); hr = NntpCreateException ( IDS_NNTPEXCEPTION_INVALID_INDEX ); goto Exit; } hr = m_rgExpires[index].Remove ( m_iadsImpl.QueryComputer(), m_iadsImpl.QueryInstance() ); if ( FAILED(hr) ) { goto Exit; } // Slide the array down by one position: _ASSERT ( m_rgExpires ); DWORD cPositionsToSlide; cPositionsToSlide = (m_cCount - 1) - index; _ASSERT ( cPositionsToSlide < m_cCount ); if ( cPositionsToSlide > 0 ) { CExpirationPolicy temp; // Save the deleted binding in temp: CopyMemory ( &temp, &m_rgExpires[index], sizeof ( CExpirationPolicy ) ); // Move the array down one: MoveMemory ( &m_rgExpires[index], &m_rgExpires[index + 1], sizeof ( CExpirationPolicy ) * cPositionsToSlide ); // Put the deleted binding on the end (so it gets destructed): CopyMemory ( &m_rgExpires[m_cCount - 1], &temp, sizeof ( CExpirationPolicy ) ); // Zero out the temp binding: ZeroMemory ( &temp, sizeof ( CExpirationPolicy ) ); } m_cCount--; Exit: TRACE_HRESULT(hr); TraceFunctLeave (); return hr; } long CNntpAdminExpiration::IndexFromID ( long dwExpireId ) { TraceFunctEnter ( "CNntpAdminExpiration::IndexFromID" ); DWORD i; if ( m_rgExpires == NULL ) { return -1; } _ASSERT ( !IsBadReadPtr ( m_rgExpires, sizeof ( CExpirationPolicy ) * m_cCount ) ); for ( i = 0; i < m_cCount; i++ ) { _ASSERT ( m_rgExpires[i].m_dwExpireId != 0 ); if ( (DWORD) dwExpireId == m_rgExpires[i].m_dwExpireId ) { TraceFunctLeave (); return i; } } TraceFunctLeave (); return (DWORD) -1; } // // Use RPCs instead of direct metabase calls: // #if 0 STDMETHODIMP CNntpAdminExpiration::Enumerate ( ) { TraceFunctEnter ( "CNntpadminExpiration::Enumerate" ); HRESULT hr = NOERROR; CComPtr pMetabase; // Reset our last enumeration: delete [] m_rgExpires; m_rgExpires = NULL; m_cCount = 0; m_fEnumerated = FALSE; // Get the metabase pointer: hr = m_mbFactory.GetMetabaseObject ( m_iadsImpl.QueryComputer(), m_iadsImpl.QueryInstance() ); if ( FAILED(hr) ) { goto Exit; } // Enumerate the policies: hr = EnumerateMetabaseExpirationPolicies ( pMetabase ); if ( FAILED(hr) ) { goto Exit; } Exit: TRACE_HRESULT(hr); TraceFunctLeave (); return hr; } STDMETHODIMP CNntpAdminExpiration::GetNth ( DWORD lIndex ) { HRESULT hr = NOERROR; // Did we enumerate first? if ( m_rgExpires == NULL ) { return NntpCreateException ( IDS_NNTPEXCEPTION_DIDNT_ENUMERATE ); } // Is the index valid? if ( lIndex < 0 || (DWORD) lIndex >= m_cCount ) { return NntpCreateException ( IDS_NNTPEXCEPTION_INVALID_INDEX ); } // // Copy the properties from m_rgExpires [ lIndex ] to member variables: // _ASSERT ( lIndex >= 0 ); _ASSERT ( (DWORD) lIndex < m_cCount ); _ASSERT ( m_rgExpires != NULL ); m_expireCurrent = m_rgExpires[ (DWORD) lIndex ]; // Check to make sure the strings were copied okay: if ( !m_expireCurrent.CheckValid() ) { return E_OUTOFMEMORY; } m_bvChangedFields = 0; _ASSERT ( m_expireCurrent.CheckValid() ); // ( CComBSTR handles free-ing of old properties ) return NOERROR; } STDMETHODIMP CNntpAdminExpiration::FindID ( DWORD lID, DWORD * plIndex ) { TraceFunctEnter ( "CNntpAdminExpiration::FindID" ); HRESULT hr = NOERROR; DWORD i; _ASSERT ( IS_VALID_OUT_PARAM ( plIndex ) ); *plIndex = IndexFromID ( lID ); TraceFunctLeave (); return hr; } STDMETHODIMP CNntpAdminExpiration::Add ( ) { TraceFunctEnter ( "CNntpAdminExpiration::Add" ); HRESULT hr = NOERROR; CComPtr pMetabase; // Get the metabase pointer: hr = m_mbFactory.GetMetabaseObject ( m_iadsImpl.QueryComputer(), m_iadsImpl.QueryInstance() ); if ( FAILED(hr) ) { goto Exit; } hr = AddPolicyToMetabase ( pMetabase ); if ( FAILED(hr) ) { goto Exit; } m_bvChangedFields = 0; hr = AddPolicyToArray ( ); if ( FAILED(hr) ) { goto Exit; } Exit: TRACE_HRESULT(hr); TraceFunctLeave (); return hr; } STDMETHODIMP CNntpAdminExpiration::Set ( BOOL fFailIfChanged) { TraceFunctEnter ( "CNntpadminExpiration::Enumerate" ); HRESULT hr = NOERROR; CComPtr pMetabase; // Get the metabase pointer: hr = m_mbFactory.GetMetabaseObject ( m_iadsImpl.QueryComputer(), m_iadsImpl.QueryInstance() ); if ( FAILED(hr) ) { goto Exit; } // Set the policy: hr = SetPolicyToMetabase ( pMetabase ); if ( FAILED(hr) ) { goto Exit; } m_bvChangedFields = 0; hr = SetPolicyToArray ( ); if ( FAILED(hr) ) { goto Exit; } Exit: TRACE_HRESULT(hr); TraceFunctLeave (); return hr; } STDMETHODIMP CNntpAdminExpiration::Remove ( DWORD lID) { TraceFunctEnter ( "CNntpadminExpiration::Remove" ); HRESULT hr = NOERROR; CComPtr pMetabase; DWORD index; // Find the index of the policy to remove: index = IndexFromID ( lID ); if ( index == (DWORD) -1 ) { hr = RETURNCODETOHRESULT ( ERROR_INVALID_PARAMETER ); goto Exit; } // Get the metabase pointer: hr = m_mbFactory.GetMetabaseObject ( m_iadsImpl.QueryComputer(), m_iadsImpl.QueryInstance() ); if ( FAILED(hr) ) { goto Exit; } // Remove the current policy: hr = RemovePolicyFromMetabase ( pMetabase, index ); if ( FAILED(hr) ) { goto Exit; } hr = RemovePolicyFromArray ( index ); if ( FAILED(hr) ) { goto Exit; } Exit: TRACE_HRESULT(hr); TraceFunctLeave (); return hr; } HRESULT CNntpAdminExpiration::EnumerateMetabaseExpirationPolicies ( IMSAdminBase * pMetabase) { TraceFunctEnter ( "CNE::EnumerateMetabaseExpirationPolicies" ); _ASSERT ( pMetabase ); HRESULT hr = NOERROR; char szExpirationPath[ METADATA_MAX_NAME_LEN ]; METADATA_HANDLE hExpiration = NULL; CMetabaseKey mkeyExpiration ( pMetabase ); DWORD cExpires; DWORD i; _ASSERT ( m_dwServiceInstance != 0 ); hr = CreateSubkeyOfInstanceKey ( pMetabase, NNTP_MD_ROOT_PATH, m_dwServiceInstance, NNTP_MD_EXPIRES_PATH, &hExpiration ); if ( FAILED(hr) ) { goto Exit; } mkeyExpiration.Attach ( hExpiration ); // Count the items under the /LM/NntpSvc/Expires/ key: hr = mkeyExpiration.GetCustomChildCount ( IsKeyValidExpire, &cExpires ); if ( FAILED (hr) ) { goto Exit; } if ( cExpires != 0 ) { // Allocate the expiration policy array: m_rgExpires = new CExpirationPolicy [ cExpires ]; mkeyExpiration.BeginChildEnumeration (); for ( i = 0; i < cExpires; i++ ) { char szName[ METADATA_MAX_NAME_LEN ]; DWORD dwID; hr = mkeyExpiration.NextCustomChild ( IsKeyValidExpire, szName ); _ASSERT ( SUCCEEDED(hr) ); hr = m_rgExpires[i].GetFromMetabase ( &mkeyExpiration, szName ); if ( FAILED (hr) ) { goto Exit; } } } m_cCount = cExpires; m_fEnumerated = TRUE; _ASSERT ( SUCCEEDED(hr) ); Exit: if ( FAILED(hr) ) { delete [] m_rgExpires; m_rgExpires = NULL; m_cCount = 0; m_fEnumerated = FALSE; } TraceFunctLeave (); return hr; } HRESULT CNntpAdminExpiration::AddPolicyToMetabase ( IMSAdminBase * pMetabase) { TraceFunctEnter ( "CNE::AddPolicyToMetabase" ); _ASSERT ( pMetabase ); HRESULT hr = NOERROR; char szExpirationPath [ METADATA_MAX_NAME_LEN ]; METADATA_HANDLE hExpiration = NULL; CMetabaseKey mkeyExpiration ( pMetabase ); char szNewId [ METADATA_MAX_NAME_LEN ]; DWORD dwNewId; if ( !m_expireCurrent.CheckPolicyProperties ( ) ) { hr = RETURNCODETOHRESULT ( ERROR_INVALID_PARAMETER ); goto Exit; } hr = CreateSubkeyOfInstanceKey ( pMetabase, NNTP_MD_ROOT_PATH, m_dwServiceInstance, NNTP_MD_EXPIRES_PATH, &hExpiration, METADATA_PERMISSION_WRITE ); if ( FAILED(hr) ) { goto Exit; } mkeyExpiration.Attach ( hExpiration ); hr = m_expireCurrent.AddToMetabase ( &mkeyExpiration ); if ( FAILED(hr) ) { goto Exit; } _ASSERT ( SUCCEEDED(hr) ); hr = pMetabase->SaveData ( ); if ( FAILED(hr) ) { goto Exit; } Exit: TraceFunctLeave (); return hr; } HRESULT CNntpAdminExpiration::AddPolicyToArray ( ) { TraceFunctEnter ( "CNE::AddPolicyToArray" ); HRESULT hr = NOERROR; CExpirationPolicy * rgNewPolicyArray = NULL; DWORD i; // Adjust the expiration policy array: rgNewPolicyArray = new CExpirationPolicy [ m_cCount + 1 ]; if ( rgNewPolicyArray == NULL ) { hr = E_OUTOFMEMORY; goto Exit; } // Copy the old entries: for ( i = 0; i < m_cCount; i++ ) { _ASSERT ( m_rgExpires[i].CheckValid() ); rgNewPolicyArray[i] = m_rgExpires[i]; if ( !rgNewPolicyArray[i].CheckValid() ) { hr = E_OUTOFMEMORY; goto Exit; } } // Add the new entry: _ASSERT ( m_expireCurrent.CheckValid() ); rgNewPolicyArray[m_cCount] = m_expireCurrent; if ( !rgNewPolicyArray[m_cCount].CheckValid() ) { hr = E_OUTOFMEMORY; goto Exit; } _ASSERT ( SUCCEEDED(hr) ); delete [] m_rgExpires; m_rgExpires = rgNewPolicyArray; m_cCount++; Exit: if ( FAILED(hr) ) { delete [] rgNewPolicyArray; } TRACE_HRESULT(hr); TraceFunctLeave (); return hr; } HRESULT CNntpAdminExpiration::SetPolicyToMetabase ( IMSAdminBase * pMetabase) { TraceFunctEnter ( "CNE::SetPolicyToMetabase" ); _ASSERT ( pMetabase ); HRESULT hr = NOERROR; CMetabaseKey mkeyExpiration ( pMetabase ); char szExpirationPath [ METADATA_MAX_NAME_LEN ]; if ( !m_expireCurrent.CheckPolicyProperties ( ) ) { hr = RETURNCODETOHRESULT ( ERROR_INVALID_PARAMETER ); goto Exit; } GetMDExpirationPath ( szExpirationPath, m_dwServiceInstance ); hr = mkeyExpiration.Open ( szExpirationPath, METADATA_PERMISSION_WRITE ); if ( FAILED(hr) ) { goto Exit; } _ASSERT ( m_expireCurrent.m_dwExpireId != 0 ); hr = m_expireCurrent.SendToMetabase ( &mkeyExpiration, m_bvChangedFields ); if ( FAILED(hr) ) { goto Exit; } hr = pMetabase->SaveData ( ); if ( FAILED(hr) ) { goto Exit; } Exit: TraceFunctLeave (); return hr; } HRESULT CNntpAdminExpiration::SetPolicyToArray ( ) { TraceFunctEnter ( "CNE::SetPolicyToArray" ); HRESULT hr = NOERROR; // Find the index of the current ID: DWORD i; BOOL fFound = FALSE; DWORD index; index = IndexFromID ( m_expireCurrent.m_dwExpireId ); if ( index == (DWORD) -1 ) { // Couldn't find an id that matched, but the policy was successfully // set. Just ignore: goto Exit; } _ASSERT ( index >= 0 && index < m_cCount ); m_rgExpires[index] = m_expireCurrent; if ( !m_rgExpires[index].CheckValid() ) { FatalTrace ( (LPARAM) this, "Out of memory" ); hr = E_OUTOFMEMORY; goto Exit; } Exit: TraceFunctLeave (); return hr; } HRESULT CNntpAdminExpiration::RemovePolicyFromMetabase ( IMSAdminBase * pMetabase, DWORD index) { TraceFunctEnter ( "CNE::RemovePolicyFromMetabase" ); _ASSERT ( pMetabase ); HRESULT hr = NOERROR; CMetabaseKey mkeyExpiration ( pMetabase ); char szExpirationPath [ METADATA_MAX_NAME_LEN ]; char szID [ METADATA_MAX_NAME_LEN ]; GetMDExpirationPath ( szExpirationPath, m_dwServiceInstance ); hr = mkeyExpiration.Open ( szExpirationPath, METADATA_PERMISSION_WRITE ); if ( FAILED(hr) ) { goto Exit; } _ASSERT ( index >= 0 && index < m_cCount ); wsprintfA ( szID, "expire%ud", m_rgExpires[index].m_dwExpireId ); hr = mkeyExpiration.DestroyChild ( szID ); if ( FAILED(hr) ) { goto Exit; } _ASSERT ( SUCCEEDED(hr) ); hr = pMetabase->SaveData ( ); if ( FAILED(hr) ) { goto Exit; } Exit: TraceFunctLeave (); return hr; } HRESULT CNntpAdminExpiration::RemovePolicyFromArray ( DWORD index ) { TraceFunctEnter ( "CNE::RemovePolicyFromArray" ); HRESULT hr = NOERROR; CExpirationPolicy * rgNewExpireArray = NULL; DWORD i; // !!!magnush - Should I just do a memmove and slide the entries // down, and zero out the last entry? _ASSERT ( index >= 0 && index < m_cCount ); // Adjust the Expiration policy array: if ( m_cCount > 1 ) { // Allocate a new expiration policy array: rgNewExpireArray = new CExpirationPolicy [ m_cCount - 1 ]; // Copy the items from 0 .. (current index) to the new list: for ( i = 0; i < index; i++ ) { _ASSERT ( m_rgExpires[i].CheckValid() ); rgNewExpireArray[i] = m_rgExpires[i]; if ( !rgNewExpireArray[i].CheckValid() ) { hr = E_OUTOFMEMORY; goto Exit; } } // Copy the items from (current index + 1) .. m_cCount to the new list: for ( i = index + 1; i < m_cCount; i++ ) { _ASSERT ( m_rgExpires[i].CheckValid() ); rgNewExpireArray[i - 1] = m_rgExpires[i]; if ( !rgNewExpireArray[i - 1].CheckValid() ) { hr = E_OUTOFMEMORY; goto Exit; } } } _ASSERT ( SUCCEEDED(hr) ); // Replace the old expiration list with the new one: delete [] m_rgExpires; m_rgExpires = rgNewExpireArray; m_cCount--; Exit: if ( FAILED (hr) ) { delete [] rgNewExpireArray; } TraceFunctLeave (); return hr; } long CNntpAdminExpiration::IndexFromID ( long dwID ) { TraceFunctEnter ( "CNE::IndexFromID" ); DWORD i; if ( m_rgExpires == NULL ) { DebugTrace ( (LPARAM) this, "Expire array is NULL" ); TraceFunctLeave (); return (DWORD) -1; } _ASSERT ( !IsBadReadPtr ( m_rgExpires, sizeof ( CExpirationPolicy ) * m_cCount ) ); for ( i = 0; i < m_cCount; i++ ) { if ( m_rgExpires[i].m_dwExpireId == dwID ) { DebugTraceX ( (LPARAM) this, "Found ID: %d, index = ", dwID, i ); TraceFunctLeave (); return i; } } DebugTraceX ( (LPARAM) this, "Failed to find ID: %d", dwID ); TraceFunctLeave (); return (DWORD) -1; } #endif