|
|
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
feedinfo.cpp
Abstract:
Author:
Magnus Hedlund (MagnusH) --
Revision History:
Kangrong Yan ( KangYan ) Feb-28-1998 Feed config change no longer calls NNTP RPC. It directly writes to MB and synchronize with NNTPSVC's response in the metabase.
--*/
#include "stdafx.h"
#include "oleutil.h"
#include "nntpcmn.h"
#include "nntptype.h"
#include "nntpapi.h"
#include "feedpach.h"
#include "feeds.h"
#include "feedinfo.h"
#include <lmapibuf.h>
BOOL IsInboundFeed ( CFeed * pFeed ) { DWORD dwType = pFeed->m_FeedType;
return FEED_IS_PASSIVE ( dwType ) || FEED_IS_PULL ( dwType ); }
BOOL IsOutboundFeed ( CFeed * pFeed ) { DWORD dwType = pFeed->m_FeedType;
return FEED_IS_PUSH ( dwType ); }
NNTP_FEED_SERVER_TYPE FeedTypeToEnum ( FEED_TYPE ft ) { NNTP_FEED_SERVER_TYPE type = NNTP_FEED_TYPE_PEER;
if ( FEED_IS_PEER ( ft ) ) { type = NNTP_FEED_TYPE_PEER; } else if ( FEED_IS_MASTER ( ft ) ) { type = NNTP_FEED_TYPE_MASTER; } else if ( FEED_IS_SLAVE ( ft ) ) { type = NNTP_FEED_TYPE_SLAVE; } else { _ASSERT ( FALSE ); }
return type; }
void EnumToFeedType ( NNTP_FEED_SERVER_TYPE type, FEED_TYPE & ftMask ) { DWORD dwType = 0;
// Clear out the feed type from the mask
ftMask &= ~FEED_REMOTE_MASK;
switch ( type ) { case NNTP_FEED_TYPE_PEER: dwType = FEED_TYPE_PEER; break;
case NNTP_FEED_TYPE_MASTER: dwType = FEED_TYPE_MASTER; break;
case NNTP_FEED_TYPE_SLAVE: dwType = FEED_TYPE_SLAVE; break; }
// Move the feed type into the mask:
ftMask |= dwType; }
// Must define THIS_FILE_* macros to use NntpCreateException()
#define THIS_FILE_HELP_CONTEXT 0
#define THIS_FILE_PROG_ID _T("Nntpadm.Feeds.1")
#define THIS_FILE_IID IID_INntpAdminFeeds
CFeed::CFeed ( ) // CComBSTR's are automatically initialized to NULL
{ //
// Initialize all properties to 0
//
m_dwFeedId = 0; m_dwPairFeedId = 0; m_fAllowControlMessages = FALSE; m_dwAuthenticationType = AUTH_PROTOCOL_NONE; m_dwConcurrentSessions = 0; m_fCreateAutomatically = FALSE; m_dwFeedInterval = 0; m_datePullNews = 0; m_dwMaxConnectionAttempts = 0; m_dwSecurityType = 0; m_dwOutgoingPort = 0;
m_FeedType = FEED_TYPE_PULL | FEED_TYPE_PEER; m_fEnabled = TRUE; }
CFeed::~CFeed ( ) { AssertValid ();
// CComBSTR's are automatically freed.
}
void CFeed::Destroy () { AssertValid ();
// Need to empty all strings:
m_mszDistributions.Empty(); m_mszNewsgroups.Empty(); m_strRemoteServer.Empty(); m_strUucpName.Empty(); m_strAccountName.Empty(); m_strPassword.Empty(); m_strTempDirectory.Empty(); }
HRESULT CFeed::CreateFeed ( CFeed ** ppNewFeed ) { CFeed * pFeedNew = new CFeed;
if ( pFeedNew ) { *ppNewFeed = pFeedNew; return NOERROR; } else { *ppNewFeed = NULL; return E_OUTOFMEMORY; } }
HRESULT CFeed::CreateFeedFromFeedInfo ( LPNNTP_FEED_INFO pFeedInfo, CFeed ** ppNewFeed ) { HRESULT hr = NOERROR; CFeed * pFeedNew;
*ppNewFeed = NULL;
hr = CreateFeed ( &pFeedNew ); BAIL_ON_FAILURE ( hr );
hr = pFeedNew->FromFeedInfo ( pFeedInfo ); BAIL_ON_FAILURE ( hr );
*ppNewFeed = pFeedNew;
Exit: return hr; }
HRESULT CFeed::CreateFeedFromINntpOneWayFeed ( INntpOneWayFeed * pFeed, CFeed ** ppNewFeed ) { HRESULT hr = NOERROR; CFeed * pFeedNew = NULL;
*ppNewFeed = NULL;
hr = CreateFeed ( &pFeedNew ); BAIL_ON_FAILURE ( hr );
hr = pFeedNew->FromINntpOneWayFeed ( pFeed ); BAIL_ON_FAILURE ( hr );
*ppNewFeed = pFeedNew;
return hr;
Exit: if (pFeedNew) delete pFeedNew; return hr; }
const CFeed & CFeed::operator= ( const CFeed & feed ) { AssertValid (); feed.AssertValid ();
// Check for assignment to self:
if ( &feed == this ) { return *this; }
// Empty the old feed values:
this->Destroy ();
// Copy all member variables:
m_dwFeedId = feed.m_dwFeedId; m_dwPairFeedId = feed.m_dwPairFeedId; m_FeedType = feed.m_FeedType; m_fAllowControlMessages = feed.m_fAllowControlMessages; m_dwAuthenticationType = feed.m_dwAuthenticationType; m_dwConcurrentSessions = feed.m_dwConcurrentSessions; m_fCreateAutomatically = feed.m_fCreateAutomatically; m_fEnabled = feed.m_fEnabled; m_mszDistributions = feed.m_mszDistributions; m_dwFeedInterval = feed.m_dwFeedInterval; m_datePullNews = feed.m_datePullNews; m_dwMaxConnectionAttempts = feed.m_dwMaxConnectionAttempts; m_mszNewsgroups = feed.m_mszNewsgroups; m_dwSecurityType = feed.m_dwSecurityType; m_dwOutgoingPort = feed.m_dwOutgoingPort; m_strRemoteServer = feed.m_strRemoteServer; m_strUucpName = feed.m_strUucpName; m_strAccountName = feed.m_strAccountName; m_strPassword = feed.m_strPassword; m_strTempDirectory = feed.m_strTempDirectory;
m_strRemoteServer = feed.m_strRemoteServer; m_EnumType = feed.m_EnumType;
return *this; }
BOOL CFeed::CheckValid ( ) const { AssertValid ();
// Check Strings:
if ( !m_mszDistributions || !m_mszNewsgroups || !m_strUucpName || !m_strAccountName || !m_strPassword || !m_strRemoteServer ) {
return FALSE; }
return TRUE; }
HRESULT CFeed::get_FeedAction ( NNTP_FEED_ACTION * feedaction ) { AssertValid ();
NNTP_FEED_ACTION result;
switch ( m_FeedType & FEED_ACTION_MASK ) { case FEED_TYPE_PULL: result = NNTP_FEED_ACTION_PULL; break;
case FEED_TYPE_PUSH: result = NNTP_FEED_ACTION_PUSH; break;
case FEED_TYPE_PASSIVE: result = NNTP_FEED_ACTION_ACCEPT; break;
default: _ASSERT ( FALSE ); result = NNTP_FEED_ACTION_PULL; }
*feedaction = result; return NOERROR; }
HRESULT CFeed::put_FeedAction ( NNTP_FEED_ACTION feedaction ) { AssertValid ();
FEED_TYPE ftNew;
ftNew = m_FeedType & (~FEED_ACTION_MASK);
switch ( feedaction ) { case NNTP_FEED_ACTION_PULL: ftNew |= FEED_TYPE_PULL; break;
case NNTP_FEED_ACTION_PUSH: ftNew |= FEED_TYPE_PUSH; break;
case NNTP_FEED_ACTION_ACCEPT: ftNew |= FEED_TYPE_PASSIVE; break;
default: _ASSERT ( FALSE ); return TranslateFeedError ( ERROR_INVALID_PARAMETER, FEED_PARM_FEEDTYPE ); }
m_FeedType = ftNew; return NOERROR; }
HRESULT CFeed::FromFeedInfo ( const NNTP_FEED_INFO * pFeedInfo ) { AssertValid ();
FILETIME ftPullNewsLocal; SYSTEMTIME stPullNews;
this->Destroy ();
m_dwFeedId = pFeedInfo->FeedId; m_dwPairFeedId = pFeedInfo->FeedPairId; m_FeedType = pFeedInfo->FeedType; m_fAllowControlMessages = pFeedInfo->fAllowControlMessages; m_dwAuthenticationType = pFeedInfo->AuthenticationSecurityType; m_dwConcurrentSessions = pFeedInfo->ConcurrentSessions; m_fCreateAutomatically = pFeedInfo->AutoCreate; m_fEnabled = pFeedInfo->Enabled; m_mszDistributions = pFeedInfo->Distribution ? pFeedInfo->Distribution : _T("\0");
if ( !FEED_IS_PULL (m_FeedType) || ( pFeedInfo->PullRequestTime.dwLowDateTime == 0 && pFeedInfo->PullRequestTime.dwHighDateTime == 0 ) ) { //
// Not a pull feed - so default to something reasonable here:
//
GetLocalTime ( &stPullNews ); } else { FileTimeToLocalFileTime ( &pFeedInfo->PullRequestTime, &ftPullNewsLocal ); FileTimeToSystemTime ( &ftPullNewsLocal, &stPullNews ); } SystemTimeToVariantTime ( &stPullNews, &m_datePullNews );
m_dwFeedInterval = pFeedInfo->FeedInterval; m_dwMaxConnectionAttempts = pFeedInfo->MaxConnectAttempts; m_mszNewsgroups = pFeedInfo->Newsgroups ? pFeedInfo->Newsgroups : _T("\0"); m_dwSecurityType = pFeedInfo->SessionSecurityType; m_dwOutgoingPort = pFeedInfo->OutgoingPort; m_strUucpName = pFeedInfo->UucpName ? pFeedInfo->UucpName : _T(""); m_strAccountName = pFeedInfo->NntpAccountName ? pFeedInfo->NntpAccountName : _T(""); m_strPassword = pFeedInfo->NntpPassword ? pFeedInfo->NntpPassword : _T(""); m_strTempDirectory = pFeedInfo->FeedTempDirectory;
if ( pFeedInfo->Distribution ) { _ASSERT ( m_mszDistributions.SizeInBytes () == pFeedInfo->cbDistribution ); } _ASSERT ( m_mszNewsgroups.SizeInBytes () == pFeedInfo->cbNewsgroups );
m_strRemoteServer = pFeedInfo->ServerName ? pFeedInfo->ServerName : _T(""); m_EnumType = FeedTypeToEnum ( m_FeedType );
// Check Strings:
if ( !CheckValid () ) { return E_OUTOFMEMORY; } return NOERROR; }
HRESULT CFeed::ToFeedInfo ( LPNNTP_FEED_INFO pFeedInfo ) { TraceFunctEnter ( "CFeed::ToFeedInfo" );
AssertValid (); _ASSERT ( IS_VALID_OUT_PARAM ( pFeedInfo ) );
HRESULT hr = NOERROR;
SYSTEMTIME stPullNews; FILETIME ftPullNewsLocal;
EnumToFeedType ( m_EnumType, m_FeedType );
ZeroMemory ( pFeedInfo, sizeof (*pFeedInfo) );
pFeedInfo->ServerName = m_strRemoteServer; pFeedInfo->FeedId = m_dwFeedId; pFeedInfo->FeedPairId = m_dwPairFeedId; pFeedInfo->FeedType = m_FeedType; pFeedInfo->fAllowControlMessages = m_fAllowControlMessages; pFeedInfo->AuthenticationSecurityType = m_dwAuthenticationType; pFeedInfo->ConcurrentSessions = m_dwConcurrentSessions; pFeedInfo->AutoCreate = m_fCreateAutomatically; pFeedInfo->Enabled = m_fEnabled;
//
// Convert time formats:
//
VariantTimeToSystemTime ( m_datePullNews, &stPullNews );
SystemTimeToFileTime ( &stPullNews, &ftPullNewsLocal );
LocalFileTimeToFileTime ( &ftPullNewsLocal, &pFeedInfo->PullRequestTime); ZeroMemory ( &pFeedInfo->StartTime, sizeof ( FILETIME ) );
pFeedInfo->FeedInterval = m_dwFeedInterval; pFeedInfo->MaxConnectAttempts = m_dwMaxConnectionAttempts; pFeedInfo->SessionSecurityType = m_dwSecurityType; pFeedInfo->OutgoingPort = m_dwOutgoingPort; pFeedInfo->ServerName = m_strRemoteServer; pFeedInfo->UucpName = m_strUucpName; pFeedInfo->cbUucpName = STRING_BYTE_LENGTH ( m_strUucpName ); pFeedInfo->NntpAccountName = m_strAccountName; pFeedInfo->cbAccountName = STRING_BYTE_LENGTH ( m_strAccountName ); pFeedInfo->NntpPassword = m_strPassword; pFeedInfo->cbPassword = STRING_BYTE_LENGTH ( m_strPassword ); pFeedInfo->FeedTempDirectory = m_strTempDirectory; pFeedInfo->cbFeedTempDirectory = STRING_BYTE_LENGTH ( m_strTempDirectory );
pFeedInfo->Distribution = (LPWSTR) (LPCWSTR) m_mszDistributions; pFeedInfo->cbDistribution = m_mszDistributions.SizeInBytes(); pFeedInfo->Newsgroups = (LPWSTR) (LPCWSTR) m_mszNewsgroups; pFeedInfo->cbNewsgroups = m_mszNewsgroups.SizeInBytes();
TraceFunctLeave (); return hr; }
HRESULT CFeed::FromINntpOneWayFeed ( INntpOneWayFeed * pFeed ) { AssertValid ();
CNntpOneWayFeed * pPrivateFeed;
pPrivateFeed = (CNntpOneWayFeed *) pFeed;
*this = pPrivateFeed->m_feed;
if ( !CheckValid () ) { return E_OUTOFMEMORY; } return NOERROR; }
HRESULT CFeed::ToINntpOneWayFeed ( INntpOneWayFeed ** ppFeed ) { AssertValid ();
HRESULT hr = NOERROR; CComObject<CNntpOneWayFeed> * pFeed = NULL;
hr = CComObject<CNntpOneWayFeed>::CreateInstance ( &pFeed ); if ( FAILED(hr) ) { goto Exit; }
pFeed->m_feed = *this; if ( !pFeed->m_feed.CheckValid() ) { hr = E_OUTOFMEMORY; goto Exit; }
hr = pFeed->QueryInterface ( IID_INntpOneWayFeed, (void **) ppFeed ); if ( FAILED(hr) ) { goto Exit; }
Exit: if ( FAILED(hr) ) { delete pFeed; } return hr; }
HRESULT CFeed::CheckConfirm( IN DWORD dwFeedId, IN DWORD dwInstanceId, IN CMetabaseKey* pMK, OUT PDWORD pdwErr, OUT PDWORD pdwErrMask ) { TraceFunctEnter( "CFeed::CheckConfirm" ); _ASSERT( pMK ); _ASSERT( dwFeedId > 0 ); HRESULT hr; const DWORD dwMaxAttempts = 10; const DWORD dwWaitMilliSeconds = 500; DWORD dwHandShake;
for ( int i = 0; i < dwMaxAttempts; i++ ) { hr = OpenKey( dwFeedId, pMK, METADATA_PERMISSION_READ, dwInstanceId ); if ( FAILED( hr ) ) { if ( HRESULTTOWIN32( hr ) == ERROR_PATH_BUSY ) { Sleep( dwWaitMilliSeconds ); continue; } else { ErrorTrace(0, "Open key fail with 0x%x", hr ); return hr; } }
//
// getting the handshake
//
hr = pMK->GetDword( MD_FEED_HANDSHAKE, &dwHandShake ); if ( FAILED( hr ) ) { // shouldn't happen , it's an error
pMK->Close(); ErrorTrace(0, "Get handshake fail with 0x%x", hr ); return hr; }
if ( dwHandShake != FEED_UPDATE_CONFIRM ) { pMK->Close(); Sleep( dwWaitMilliSeconds ); continue; }
//
// Now get error / masks
//
hr = pMK->GetDword( MD_FEED_ADMIN_ERROR, pdwErr ); if ( FAILED( hr ) ) { // the server is possibly not
// writing the confirm /error
// in good sequence, lets give
// it more chances
pMK->Close(); Sleep( dwWaitMilliSeconds ); continue; }
hr = pMK->GetDword( MD_FEED_ERR_PARM_MASK, pdwErrMask ); if ( FAILED( hr ) ) { // same comments as above
pMK->Close(); Sleep( dwWaitMilliSeconds ); continue; }
//
// Now we are done
//
pMK->Close(); break; }
if ( i == dwMaxAttempts ) return E_FAIL; else return S_OK; }
HRESULT CFeed::Add ( LPCWSTR strServer, DWORD dwInstance, CMetabaseKey* pMK ) { TraceFunctEnter ( "CFeed::Add" );
AssertValid ();
HRESULT hr = NOERROR; DWORD dwError = NOERROR; DWORD dwParmErr = 0; NNTP_FEED_INFO feedinfo; DWORD dwFeedId = 0;
FillMemory ( &feedinfo, sizeof (feedinfo), 0 );
hr = ToFeedInfo ( &feedinfo ); if ( FAILED(hr) ) { goto Exit; }
feedinfo.FeedId = 0;
//
// KangYan: RPC goes away. We use metabase writes
//
hr = AddFeedToMB( &feedinfo, pMK, &dwParmErr, dwInstance, &dwFeedId ); if ( FAILED( hr ) ) { ErrorTrace(0, "Add to MB fail with 0x%x", hr ); goto Exit; }
hr = CheckConfirm( dwFeedId, dwInstance, pMK, &dwError, &dwParmErr ); if ( FAILED( hr ) ) { ErrorTrace( 0, "Check confirm fail with 0x%x", hr ); goto Exit; }
if ( dwError != NOERROR ) { ErrorTraceX ( (LPARAM) this, "Failed to add feed: %x (%x)", dwError, dwParmErr ); hr = TranslateFeedError ( dwError, dwParmErr ); goto Exit; }
this->m_dwFeedId = dwFeedId;
Exit: TraceFunctLeave (); return hr; }
HRESULT CFeed::Set ( LPCWSTR strServer, DWORD dwInstance, CMetabaseKey* pMK ) { TraceFunctEnter ( "CFeed::Set" );
AssertValid ();
HRESULT hr = NOERROR; DWORD dwError = NOERROR; DWORD dwParmErr = 0; NNTP_FEED_INFO feedinfo;
FillMemory ( &feedinfo, sizeof (feedinfo), 0 );
hr = ToFeedInfo ( &feedinfo ); if ( FAILED(hr) ) { goto Exit; }
//
// KangYan: RPC goes away. We use metabase writes
//
hr = SetFeedToMB( &feedinfo, pMK, &dwParmErr, dwInstance ); if ( FAILED( hr ) ) { ErrorTrace(0, "Set MB fail with 0x%x", hr ); goto Exit; }
hr = CheckConfirm( feedinfo.FeedId, dwInstance, pMK, &dwError, &dwParmErr ); if ( FAILED( hr ) ) { ErrorTrace(0, "Check confirm fail with 0x%x", hr ); goto Exit; }
if ( dwError != NOERROR ) { ErrorTraceX ( (LPARAM) this, "Failed to set feed[%d]: %x (%x)", m_dwFeedId, dwError, dwParmErr ); hr = TranslateFeedError ( dwError, dwParmErr ); goto Exit; }
Exit: TraceFunctLeave (); return hr; }
HRESULT CFeed::Remove ( LPCWSTR strServer, DWORD dwInstance, CMetabaseKey* pMK ) { TraceFunctEnter ( "CFeed::Remove" );
AssertValid ();
HRESULT hr = NOERROR; DWORD dwError = NOERROR;
hr = DeleteFeed( m_dwFeedId, pMK, dwInstance ); if ( FAILED( hr ) ) { dwError = HRESULTTOWIN32( hr ); ErrorTraceX ( (LPARAM) this, "Failed to remove feed[%d]: %x", m_dwFeedId, hr ); hr = TranslateFeedError ( dwError ); goto Exit; }
Exit: TraceFunctLeave (); return hr; }
HRESULT CFeed::SetPairId ( LPCWSTR strServer, DWORD dwInstance, DWORD dwPairId, CMetabaseKey* pMK ) { TraceFunctEnter ( "CFeed::SetPairID" );
AssertValid ();
HRESULT hr = NOERROR; DWORD dwError = NOERROR; DWORD dwParmErr = 0; NNTP_FEED_INFO feedinfo;
//
// Assume that this feed was just Added/Set to the server.
//
_ASSERT ( dwPairId != m_dwFeedId ); m_dwPairFeedId = dwPairId;
FillMemory ( &feedinfo, sizeof (feedinfo), 0 );
hr = ToFeedInfo ( &feedinfo ); if ( FAILED(hr) ) { goto Exit; }
//
// KangYan: RPC goes away. We use metabase writes
//
hr = SetFeedToMB( &feedinfo, pMK, &dwParmErr, dwInstance ); if ( FAILED( hr ) ) { ErrorTrace(0, "Set MB fail with 0x%x", hr ); goto Exit; }
hr = CheckConfirm( feedinfo.FeedId, dwInstance, pMK, &dwError, &dwParmErr ); if ( FAILED( hr ) ) { ErrorTrace(0, "Check confirm fail with 0x%x", hr ); goto Exit; }
if ( dwError != NOERROR ) { ErrorTraceX ( (LPARAM) this, "Failed to set feed[%d]: %x (%x)", m_dwFeedId, dwError, dwParmErr ); hr = TranslateFeedError ( dwError, dwParmErr ); goto Exit; }
Exit: TraceFunctLeave (); return hr; }
DWORD GetBitPosition ( DWORD dwValue ) { _ASSERT ( dwValue != 0 ); // _ASSERT ( Only one bit should be on );
DWORD dwResult; DWORD dwTemp;
for ( dwTemp = dwValue, dwResult = (DWORD) -1; dwTemp != 0; dwTemp = dwTemp >> 1, dwResult++ ) { // Empty for
// Make sure there is at most one bit on:
_ASSERT ( !(dwTemp & 1) || dwTemp == 1 ); }
return dwResult; }
HRESULT CFeed::TranslateFeedError ( DWORD dwErrorCode, DWORD dwParmErr ) { HRESULT hr;
_ASSERT ( dwErrorCode != NOERROR );
if ( dwErrorCode != ERROR_INVALID_PARAMETER || dwParmErr == 0 || dwParmErr == (DWORD) -1 ) { hr = RETURNCODETOHRESULT ( dwErrorCode ); } else { DWORD dwBitPosition; DWORD nID;
dwBitPosition = GetBitPosition ( dwParmErr ); nID = IDS_FEED_PARM_ERR_BASE + dwBitPosition;
hr = NntpCreateException ( nID ); }
return hr; }
#ifdef DEBUG
void CFeed::AssertValid ( ) const { _ASSERT ( !IsBadWritePtr ( (void *) this, sizeof (*this) ) );
//
// !!!magnush - Add more debug code here
//
}
#endif
/////////////////////////////////////////////////////////////////////
//
// CFeedPair Implementation
//
CFeedPair::CFeedPair () : m_type ( NNTP_FEED_TYPE_PEER ), m_pInbound ( NULL ), m_pOutbound ( NULL ), m_pNext ( NULL ) { }
CFeedPair::~CFeedPair () { AssertValid ();
Destroy (); }
void CFeedPair::Destroy () { AssertValid ();
// !!!magnush - Fix reference counting problem here
delete m_pInbound; delete m_pOutbound;
m_pInbound = NULL; m_pOutbound = NULL; }
HRESULT CFeedPair::CreateFeedPair ( CFeedPair ** ppNewFeedPair, BSTR strRemoteServer, NNTP_FEED_SERVER_TYPE type ) { _ASSERT ( IS_VALID_STRING (strRemoteServer) );
HRESULT hr = NOERROR; CFeedPair * pNewFeedPair;
*ppNewFeedPair = NULL;
// Allocate a new feed pair:
pNewFeedPair = new CFeedPair; if ( pNewFeedPair == NULL ) { BAIL_WITH_FAILURE ( hr, E_OUTOFMEMORY ); }
// Copy properties:
pNewFeedPair->m_strRemoteServer = strRemoteServer; pNewFeedPair->m_type = type;
// Check for failed copy:
if ( pNewFeedPair->m_strRemoteServer == NULL ) { BAIL_WITH_FAILURE ( hr, E_OUTOFMEMORY ); }
// Set the out parameter to the new feed:
*ppNewFeedPair = pNewFeedPair;
Exit: if ( FAILED(hr) ) { delete pNewFeedPair; } return hr; }
HRESULT CFeedPair::AddFeed ( CFeed * pFeed ) { AssertValid ();
HRESULT hr = NOERROR;
_ASSERT ( IS_VALID_STRING ( m_strRemoteServer ) ); _ASSERT ( IS_VALID_STRING ( pFeed->m_strRemoteServer ) );
//
// Check error conditions:
// 1. Different remote server name
// 2. Different feed type
// 3. Two inbound feeds
// 4. Two outbound feeds
// 5. Bad feed type
//
if ( lstrcmpi ( m_strRemoteServer, pFeed->m_strRemoteServer ) != 0 ) { BAIL_WITH_FAILURE ( hr, E_FAIL ); }
if ( m_type != pFeed->m_EnumType ) { BAIL_WITH_FAILURE ( hr, E_FAIL ); }
if ( IsInboundFeed ( pFeed ) && m_pInbound != NULL ) { BAIL_WITH_FAILURE ( hr, E_FAIL ); }
if ( IsOutboundFeed ( pFeed ) && m_pOutbound != NULL ) { BAIL_WITH_FAILURE ( hr, E_FAIL ); }
if ( !IsInboundFeed ( pFeed ) && !IsOutboundFeed ( pFeed ) ) { _ASSERT (FALSE); BAIL_WITH_FAILURE ( hr, E_FAIL ); }
//
// Everything is okay so take the feed into this pair:
//
if ( IsInboundFeed ( pFeed ) ) { m_pInbound = pFeed; } else { // It's an outbound feed:
m_pOutbound = pFeed; }
Exit: return hr; }
HRESULT CFeedPair::FromINntpFeed ( INntpFeed * pFeed ) { AssertValid ();
HRESULT hr = NOERROR; CComPtr<INntpOneWayFeed> pInbound; CComPtr<INntpOneWayFeed> pOutbound; CFeed * pFeedInbound = NULL; CFeed * pFeedOutbound = NULL;
m_strRemoteServer.Empty(); pFeed->get_RemoteServer ( &m_strRemoteServer ); pFeed->get_FeedType ( &m_type );
pFeed->get_InboundFeed ( &pInbound ); pFeed->get_OutboundFeed ( &pOutbound );
if ( pInbound ) { hr = CFeed::CreateFeedFromINntpOneWayFeed ( pInbound, &pFeedInbound ); BAIL_ON_FAILURE(hr);
pFeedInbound->m_strRemoteServer = m_strRemoteServer; } if ( pOutbound ) { hr = CFeed::CreateFeedFromINntpOneWayFeed ( pOutbound, &pFeedOutbound ); BAIL_ON_FAILURE(hr);
pFeedOutbound->m_strRemoteServer = m_strRemoteServer; }
delete m_pInbound; delete m_pOutbound; m_pInbound = pFeedInbound; m_pOutbound = pFeedOutbound;
Exit: if ( FAILED(hr) ) { delete pFeedInbound; delete pFeedOutbound; }
return hr; }
HRESULT CFeedPair::ToINntpFeed ( INntpFeed ** ppFeed ) { AssertValid ();
CComObject<CNntpFeed> * pFeed = NULL;
HRESULT hr = NOERROR;
hr = CComObject<CNntpFeed>::CreateInstance ( &pFeed ); if ( FAILED(hr) ) { goto Exit; }
hr = pFeed->FromFeedPair ( this ); if ( FAILED(hr) ) { goto Exit; }
hr = pFeed->QueryInterface ( IID_INntpFeed, (void **) ppFeed ); if ( FAILED(hr) ) { goto Exit; }
Exit: return hr; }
HRESULT CFeedPair::AddIndividualFeed ( LPCWSTR strServer, DWORD dwInstance, CFeed * pFeed , CMetabaseKey* pMK ) { AssertValid ();
pFeed->m_dwPairFeedId = 0; pFeed->m_EnumType = m_type; pFeed->m_strRemoteServer = m_strRemoteServer;
return pFeed->Add ( strServer, dwInstance, pMK ); }
HRESULT CFeedPair::SetIndividualFeed ( LPCWSTR strServer, DWORD dwInstance, CFeed * pFeed, CMetabaseKey* pMK ) { AssertValid ();
pFeed->m_dwPairFeedId = 0; pFeed->m_EnumType = m_type; pFeed->m_strRemoteServer = m_strRemoteServer;
return pFeed->Set ( strServer, dwInstance, pMK ); }
HRESULT CFeedPair::SetPairIds ( LPCWSTR strServer, DWORD dwInstance, CFeed * pFeed1, CFeed * pFeed2, CMetabaseKey* pMK ) { AssertValid ();
HRESULT hr = NOERROR; DWORD dwPairId1; DWORD dwPairId2;
dwPairId1 = pFeed2 ? pFeed2->m_dwFeedId : 0; dwPairId2 = pFeed1 ? pFeed1->m_dwFeedId : 0;
if ( pFeed1 ) { hr = pFeed1->SetPairId ( strServer, dwInstance, dwPairId1, pMK ); BAIL_ON_FAILURE(hr); }
if ( pFeed2 ) { hr = pFeed2->SetPairId ( strServer, dwInstance, dwPairId2, pMK ); BAIL_ON_FAILURE(hr); }
Exit: return hr; }
HRESULT CFeedPair::AddToServer ( LPCWSTR strServer, DWORD dwInstance, CMetabaseKey* pMK ) { AssertValid ();
HRESULT hr = E_UNEXPECTED;
if ( m_pInbound ) { hr = AddIndividualFeed ( strServer, dwInstance, m_pInbound, pMK ); BAIL_ON_FAILURE(hr); }
if ( m_pOutbound ) { hr = AddIndividualFeed ( strServer, dwInstance, m_pOutbound, pMK ); BAIL_ON_FAILURE(hr); }
if ( m_pInbound && m_pOutbound ) { HRESULT hr2;
hr2 = SetPairIds ( strServer, dwInstance, m_pInbound, m_pOutbound, pMK ); _ASSERT ( SUCCEEDED(hr2) ); }
Exit: if ( FAILED(hr) ) { //
// Undo the add:
//
IErrorInfo *pErrorInfo = NULL; if (FAILED(GetErrorInfo(NULL, &pErrorInfo))) { pErrorInfo = NULL; }
if ( m_pInbound ) { m_pInbound->Remove ( strServer, dwInstance, pMK ); } if ( m_pOutbound ) { m_pOutbound->Remove ( strServer, dwInstance, pMK ); }
if (pErrorInfo != NULL) { SetErrorInfo(NULL, pErrorInfo); } } return hr; }
HRESULT CFeedPair::UndoFeedAction ( LPCWSTR strServer, DWORD dwInstance, CFeed * pNewFeed, CFeed * pOldFeed, CMetabaseKey* pMK ) { AssertValid ();
HRESULT hr = NOERROR;
if ( pNewFeed != NULL ) { if ( pOldFeed ) { hr = pOldFeed->Set ( strServer, dwInstance, pMK ); } else { hr = pNewFeed->Remove ( strServer, dwInstance, pMK ); } }
return hr; }
HRESULT CFeedPair::SetToServer ( LPCWSTR strServer, DWORD dwInstance, INntpFeed * pFeed, CMetabaseKey* pMK ) { AssertValid ();
HRESULT hr = NOERROR; CComPtr<INntpOneWayFeed> pInbound; CComPtr<INntpOneWayFeed> pOutbound; CFeed * pNewInbound = NULL; CFeed * pNewOutbound = NULL; CComBSTR strOldRemoteServer;
strOldRemoteServer = m_strRemoteServer;
pFeed->get_RemoteServer ( &m_strRemoteServer ); pFeed->get_InboundFeed ( &pInbound ); pFeed->get_OutboundFeed ( &pOutbound );
//
// Add the new feeds:
//
if ( !m_pInbound && pInbound ) { hr = CFeed::CreateFeedFromINntpOneWayFeed ( pInbound, &pNewInbound ); BAIL_ON_FAILURE(hr);
hr = AddIndividualFeed ( strServer, dwInstance, pNewInbound, pMK ); BAIL_ON_FAILURE(hr); } if ( !m_pOutbound && pOutbound ) { hr = CFeed::CreateFeedFromINntpOneWayFeed ( pOutbound, &pNewOutbound ); BAIL_ON_FAILURE(hr);
hr = AddIndividualFeed ( strServer, dwInstance, pNewOutbound, pMK ); BAIL_ON_FAILURE(hr); }
//
// Set the existing feeds:
//
if ( m_pInbound && pInbound ) { // The Inbound feed exists already, so call set on it:
hr = CFeed::CreateFeed ( &pNewInbound ); BAIL_ON_FAILURE(hr);
*pNewInbound = *m_pInbound;
hr = pNewInbound->FromINntpOneWayFeed ( pInbound ); BAIL_ON_FAILURE(hr);
hr = SetIndividualFeed ( strServer, dwInstance, pNewInbound, pMK ); BAIL_ON_FAILURE(hr); }
if ( m_pOutbound && pOutbound ) { // The Outbound feed exists already, so call set on it:
hr = CFeed::CreateFeed ( &pNewOutbound ); BAIL_ON_FAILURE(hr);
*pNewOutbound = *m_pOutbound;
hr = pNewOutbound->FromINntpOneWayFeed ( pOutbound ); BAIL_ON_FAILURE(hr);
hr = SetIndividualFeed ( strServer, dwInstance, pNewOutbound, pMK ); BAIL_ON_FAILURE(hr); } //
// Remove the deleted feeds:
//
if ( m_pInbound && !pInbound ) { HRESULT hr2;
hr2 = m_pInbound->Remove ( strServer, dwInstance, pMK ); _ASSERT ( SUCCEEDED(hr2) ); }
if ( m_pOutbound && !pOutbound ) { HRESULT hr2; hr2 = m_pOutbound->Remove ( strServer, dwInstance, pMK ); _ASSERT ( SUCCEEDED(hr2) ); }
SetPairIds ( strServer, dwInstance, pNewInbound, pNewOutbound, pMK );
_ASSERT ( SUCCEEDED(hr) );
delete m_pInbound; delete m_pOutbound; m_pInbound = pNewInbound; m_pOutbound = pNewOutbound;
Exit: if ( FAILED(hr) ) { //
// Attempt to back out the changes:
//
UndoFeedAction ( strServer, dwInstance, pNewInbound, m_pInbound, pMK );
UndoFeedAction ( strServer, dwInstance, pNewOutbound, m_pOutbound, pMK ); if ( pNewOutbound ) { if ( m_pOutbound ) { m_pOutbound->Set ( strServer, dwInstance, pMK ); } else { pNewOutbound->Remove ( strServer, dwInstance, pMK ); } }
delete pNewInbound; delete pNewOutbound;
m_strRemoteServer = strOldRemoteServer; } return hr; }
HRESULT CFeedPair::RemoveFromServer ( LPCWSTR strServer, DWORD dwInstance, CMetabaseKey* pMK ) { AssertValid ();
HRESULT hr = NOERROR;
if ( m_pInbound ) { hr = m_pInbound->Remove ( strServer, dwInstance, pMK ); } if ( m_pOutbound ) { hr = m_pOutbound->Remove ( strServer, dwInstance, pMK ); }
return hr; }
BOOL CFeedPair::ContainsFeedId ( DWORD dwFeedId ) { AssertValid ();
if ( m_pInbound && m_pInbound->m_dwFeedId == dwFeedId ) { return TRUE; } if ( m_pOutbound && m_pOutbound->m_dwFeedId == dwFeedId ) { return TRUE; }
return FALSE; }
#ifdef DEBUG
void CFeedPair::AssertValid ( ) const { _ASSERT ( !IsBadWritePtr ( (void *) this, sizeof (*this) ) );
if ( m_pInbound ) { m_pInbound->AssertValid (); }
if ( m_pOutbound ) { m_pOutbound->AssertValid (); } }
#endif
/////////////////////////////////////////////////////////////////////
//
// CFeedPairList Implementation
//
CFeedPairList::CFeedPairList () : m_cCount ( 0 ), m_pHead ( NULL ), m_pTail ( NULL ) { }
CFeedPairList::~CFeedPairList () { AssertValid (); Empty(); }
DWORD CFeedPairList::GetCount ( ) const { AssertValid ();
return m_cCount; }
void CFeedPairList::Empty ( ) { AssertValid ();
CFeedPair * pPair; CFeedPair * pKill;
pPair = m_pHead; while ( pPair ) { pKill = pPair; pPair = pPair->m_pNext; delete pKill; }
m_cCount = 0; m_pHead = NULL; m_pTail = NULL; }
CFeedPair * CFeedPairList::Item ( DWORD index ) { AssertValid ();
CFeedPair * pResult = NULL; DWORD i;
if ( index >= m_cCount ) { return NULL; }
pResult = m_pHead; _ASSERT ( pResult );
for ( i = 0; i < index; i++ ) { pResult = pResult->m_pNext; _ASSERT ( pResult ); }
return pResult; }
void CFeedPairList::Add ( CFeedPair * pFeedPair ) { AssertValid (); _ASSERT ( GetPairIndex ( pFeedPair ) == (DWORD) -1 );
pFeedPair->m_pNext = NULL;
if ( m_pTail == NULL ) { //
// Handle special case - Adding to empty list:
//
_ASSERT ( m_pHead == NULL );
m_pHead = pFeedPair; m_pTail = pFeedPair; } else { m_pTail->m_pNext = pFeedPair; m_pTail = pFeedPair; } m_cCount++; }
void CFeedPairList::Remove ( CFeedPair * pFeedPair ) { AssertValid (); _ASSERT ( GetPairIndex ( pFeedPair ) != (DWORD) -1 );
CFeedPair * pLead; CFeedPair * pFollow;
for ( pLead = m_pHead, pFollow = NULL; pLead != NULL && pLead != pFeedPair; pFollow = pLead, pLead = pLead->m_pNext ) { // Empty For
} _ASSERT ( pLead ); if ( !pLead ) { return; }
if ( pFollow != NULL ) { pFollow->m_pNext = pLead->m_pNext; } if ( m_pHead == pFeedPair ) { m_pHead = m_pHead->m_pNext; } if ( m_pTail == pFeedPair ) { m_pTail = pFollow; }
delete pFeedPair; m_cCount--; }
CFeedPair * CFeedPairList::Find ( DWORD dwFeedId ) { AssertValid (); CFeedPair * pResult;
if ( dwFeedId == 0 ) { return NULL; }
for ( pResult = m_pHead; pResult != NULL; pResult = pResult->m_pNext ) { if ( pResult->ContainsFeedId ( dwFeedId ) ) { return pResult; } }
return NULL; }
DWORD CFeedPairList::GetPairIndex ( CFeedPair * pPairToFind ) const { AssertValid (); _ASSERT ( pPairToFind );
DWORD index; CFeedPair * pFeedPair;
for ( pFeedPair = m_pHead, index = 0; pFeedPair != NULL; pFeedPair = pFeedPair->m_pNext, index++ ) {
if ( pFeedPair == pPairToFind ) { return index; } }
return (DWORD) -1; }
#ifdef DEBUG
void CFeedPairList::AssertValid ( ) const { _ASSERT ( !IsBadWritePtr ( (void *) this, sizeof (*this) ) );
// Walk the list and assert each feed pair is valid:
CFeedPair * pPair; DWORD cCount;
for ( cCount = 0, pPair = m_pHead; pPair != NULL; pPair = pPair->m_pNext, cCount++ ) { _ASSERT ( !IsBadWritePtr ( pPair, sizeof (*pPair) ) );
_ASSERT ( IS_VALID_STRING ( pPair->m_strRemoteServer ) );
_ASSERT ( pPair->m_pInbound || pPair->m_pOutbound );
if ( pPair->m_pInbound ) { _ASSERT ( IS_VALID_STRING ( pPair->m_pInbound->m_strRemoteServer ) ); _ASSERT ( !lstrcmpi ( pPair->m_pInbound->m_strRemoteServer, pPair->m_strRemoteServer ) ); } if ( pPair->m_pOutbound ) { _ASSERT ( IS_VALID_STRING ( pPair->m_pOutbound->m_strRemoteServer ) ); _ASSERT ( !lstrcmpi ( pPair->m_pOutbound->m_strRemoteServer, pPair->m_strRemoteServer ) ); } }
_ASSERT ( m_cCount == cCount ); }
#endif
|