Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1483 lines
34 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. feedinfo.cpp
  5. Abstract:
  6. Author:
  7. Magnus Hedlund (MagnusH) --
  8. Revision History:
  9. Kangrong Yan ( KangYan ) Feb-28-1998
  10. Feed config change no longer calls NNTP RPC. It directly writes to MB
  11. and synchronize with NNTPSVC's response in the metabase.
  12. --*/
  13. #include "stdafx.h"
  14. #include "oleutil.h"
  15. #include "nntpcmn.h"
  16. #include "nntptype.h"
  17. #include "nntpapi.h"
  18. #include "feedpach.h"
  19. #include "feeds.h"
  20. #include "feedinfo.h"
  21. #include <lmapibuf.h>
  22. BOOL IsInboundFeed ( CFeed * pFeed )
  23. {
  24. DWORD dwType = pFeed->m_FeedType;
  25. return FEED_IS_PASSIVE ( dwType ) || FEED_IS_PULL ( dwType );
  26. }
  27. BOOL IsOutboundFeed ( CFeed * pFeed )
  28. {
  29. DWORD dwType = pFeed->m_FeedType;
  30. return FEED_IS_PUSH ( dwType );
  31. }
  32. NNTP_FEED_SERVER_TYPE FeedTypeToEnum ( FEED_TYPE ft )
  33. {
  34. NNTP_FEED_SERVER_TYPE type = NNTP_FEED_TYPE_PEER;
  35. if ( FEED_IS_PEER ( ft ) ) {
  36. type = NNTP_FEED_TYPE_PEER;
  37. }
  38. else if ( FEED_IS_MASTER ( ft ) ) {
  39. type = NNTP_FEED_TYPE_MASTER;
  40. }
  41. else if ( FEED_IS_SLAVE ( ft ) ) {
  42. type = NNTP_FEED_TYPE_SLAVE;
  43. }
  44. else {
  45. _ASSERT ( FALSE );
  46. }
  47. return type;
  48. }
  49. void EnumToFeedType ( NNTP_FEED_SERVER_TYPE type, FEED_TYPE & ftMask )
  50. {
  51. DWORD dwType = 0;
  52. // Clear out the feed type from the mask
  53. ftMask &= ~FEED_REMOTE_MASK;
  54. switch ( type ) {
  55. case NNTP_FEED_TYPE_PEER:
  56. dwType = FEED_TYPE_PEER;
  57. break;
  58. case NNTP_FEED_TYPE_MASTER:
  59. dwType = FEED_TYPE_MASTER;
  60. break;
  61. case NNTP_FEED_TYPE_SLAVE:
  62. dwType = FEED_TYPE_SLAVE;
  63. break;
  64. }
  65. // Move the feed type into the mask:
  66. ftMask |= dwType;
  67. }
  68. // Must define THIS_FILE_* macros to use NntpCreateException()
  69. #define THIS_FILE_HELP_CONTEXT 0
  70. #define THIS_FILE_PROG_ID _T("Nntpadm.Feeds.1")
  71. #define THIS_FILE_IID IID_INntpAdminFeeds
  72. CFeed::CFeed ( )
  73. // CComBSTR's are automatically initialized to NULL
  74. {
  75. //
  76. // Initialize all properties to 0
  77. //
  78. m_dwFeedId = 0;
  79. m_dwPairFeedId = 0;
  80. m_fAllowControlMessages = FALSE;
  81. m_dwAuthenticationType = AUTH_PROTOCOL_NONE;
  82. m_dwConcurrentSessions = 0;
  83. m_fCreateAutomatically = FALSE;
  84. m_dwFeedInterval = 0;
  85. m_datePullNews = 0;
  86. m_dwMaxConnectionAttempts = 0;
  87. m_dwSecurityType = 0;
  88. m_dwOutgoingPort = 0;
  89. m_FeedType = FEED_TYPE_PULL | FEED_TYPE_PEER;
  90. m_fEnabled = TRUE;
  91. }
  92. CFeed::~CFeed ( )
  93. {
  94. AssertValid ();
  95. // CComBSTR's are automatically freed.
  96. }
  97. void CFeed::Destroy ()
  98. {
  99. AssertValid ();
  100. // Need to empty all strings:
  101. m_mszDistributions.Empty();
  102. m_mszNewsgroups.Empty();
  103. m_strRemoteServer.Empty();
  104. m_strUucpName.Empty();
  105. m_strAccountName.Empty();
  106. m_strPassword.Empty();
  107. m_strTempDirectory.Empty();
  108. }
  109. HRESULT CFeed::CreateFeed ( CFeed ** ppNewFeed )
  110. {
  111. CFeed * pFeedNew = new CFeed;
  112. if ( pFeedNew ) {
  113. *ppNewFeed = pFeedNew;
  114. return NOERROR;
  115. }
  116. else {
  117. *ppNewFeed = NULL;
  118. return E_OUTOFMEMORY;
  119. }
  120. }
  121. HRESULT CFeed::CreateFeedFromFeedInfo ( LPNNTP_FEED_INFO pFeedInfo, CFeed ** ppNewFeed )
  122. {
  123. HRESULT hr = NOERROR;
  124. CFeed * pFeedNew;
  125. *ppNewFeed = NULL;
  126. hr = CreateFeed ( &pFeedNew );
  127. BAIL_ON_FAILURE ( hr );
  128. hr = pFeedNew->FromFeedInfo ( pFeedInfo );
  129. BAIL_ON_FAILURE ( hr );
  130. *ppNewFeed = pFeedNew;
  131. Exit:
  132. return hr;
  133. }
  134. HRESULT CFeed::CreateFeedFromINntpOneWayFeed ( INntpOneWayFeed * pFeed, CFeed ** ppNewFeed )
  135. {
  136. HRESULT hr = NOERROR;
  137. CFeed * pFeedNew = NULL;
  138. *ppNewFeed = NULL;
  139. hr = CreateFeed ( &pFeedNew );
  140. BAIL_ON_FAILURE ( hr );
  141. hr = pFeedNew->FromINntpOneWayFeed ( pFeed );
  142. BAIL_ON_FAILURE ( hr );
  143. *ppNewFeed = pFeedNew;
  144. return hr;
  145. Exit:
  146. if (pFeedNew)
  147. delete pFeedNew;
  148. return hr;
  149. }
  150. const CFeed & CFeed::operator= ( const CFeed & feed )
  151. {
  152. AssertValid ();
  153. feed.AssertValid ();
  154. // Check for assignment to self:
  155. if ( &feed == this ) {
  156. return *this;
  157. }
  158. // Empty the old feed values:
  159. this->Destroy ();
  160. // Copy all member variables:
  161. m_dwFeedId = feed.m_dwFeedId;
  162. m_dwPairFeedId = feed.m_dwPairFeedId;
  163. m_FeedType = feed.m_FeedType;
  164. m_fAllowControlMessages = feed.m_fAllowControlMessages;
  165. m_dwAuthenticationType = feed.m_dwAuthenticationType;
  166. m_dwConcurrentSessions = feed.m_dwConcurrentSessions;
  167. m_fCreateAutomatically = feed.m_fCreateAutomatically;
  168. m_fEnabled = feed.m_fEnabled;
  169. m_mszDistributions = feed.m_mszDistributions;
  170. m_dwFeedInterval = feed.m_dwFeedInterval;
  171. m_datePullNews = feed.m_datePullNews;
  172. m_dwMaxConnectionAttempts = feed.m_dwMaxConnectionAttempts;
  173. m_mszNewsgroups = feed.m_mszNewsgroups;
  174. m_dwSecurityType = feed.m_dwSecurityType;
  175. m_dwOutgoingPort = feed.m_dwOutgoingPort;
  176. m_strRemoteServer = feed.m_strRemoteServer;
  177. m_strUucpName = feed.m_strUucpName;
  178. m_strAccountName = feed.m_strAccountName;
  179. m_strPassword = feed.m_strPassword;
  180. m_strTempDirectory = feed.m_strTempDirectory;
  181. m_strRemoteServer = feed.m_strRemoteServer;
  182. m_EnumType = feed.m_EnumType;
  183. return *this;
  184. }
  185. BOOL CFeed::CheckValid ( ) const
  186. {
  187. AssertValid ();
  188. // Check Strings:
  189. if (
  190. !m_mszDistributions ||
  191. !m_mszNewsgroups ||
  192. !m_strUucpName ||
  193. !m_strAccountName ||
  194. !m_strPassword ||
  195. !m_strRemoteServer
  196. ) {
  197. return FALSE;
  198. }
  199. return TRUE;
  200. }
  201. HRESULT CFeed::get_FeedAction ( NNTP_FEED_ACTION * feedaction )
  202. {
  203. AssertValid ();
  204. NNTP_FEED_ACTION result;
  205. switch ( m_FeedType & FEED_ACTION_MASK ) {
  206. case FEED_TYPE_PULL:
  207. result = NNTP_FEED_ACTION_PULL;
  208. break;
  209. case FEED_TYPE_PUSH:
  210. result = NNTP_FEED_ACTION_PUSH;
  211. break;
  212. case FEED_TYPE_PASSIVE:
  213. result = NNTP_FEED_ACTION_ACCEPT;
  214. break;
  215. default:
  216. _ASSERT ( FALSE );
  217. result = NNTP_FEED_ACTION_PULL;
  218. }
  219. *feedaction = result;
  220. return NOERROR;
  221. }
  222. HRESULT CFeed::put_FeedAction ( NNTP_FEED_ACTION feedaction )
  223. {
  224. AssertValid ();
  225. FEED_TYPE ftNew;
  226. ftNew = m_FeedType & (~FEED_ACTION_MASK);
  227. switch ( feedaction ) {
  228. case NNTP_FEED_ACTION_PULL:
  229. ftNew |= FEED_TYPE_PULL;
  230. break;
  231. case NNTP_FEED_ACTION_PUSH:
  232. ftNew |= FEED_TYPE_PUSH;
  233. break;
  234. case NNTP_FEED_ACTION_ACCEPT:
  235. ftNew |= FEED_TYPE_PASSIVE;
  236. break;
  237. default:
  238. _ASSERT ( FALSE );
  239. return TranslateFeedError ( ERROR_INVALID_PARAMETER, FEED_PARM_FEEDTYPE );
  240. }
  241. m_FeedType = ftNew;
  242. return NOERROR;
  243. }
  244. HRESULT CFeed::FromFeedInfo ( const NNTP_FEED_INFO * pFeedInfo )
  245. {
  246. AssertValid ();
  247. FILETIME ftPullNewsLocal;
  248. SYSTEMTIME stPullNews;
  249. this->Destroy ();
  250. m_dwFeedId = pFeedInfo->FeedId;
  251. m_dwPairFeedId = pFeedInfo->FeedPairId;
  252. m_FeedType = pFeedInfo->FeedType;
  253. m_fAllowControlMessages = pFeedInfo->fAllowControlMessages;
  254. m_dwAuthenticationType = pFeedInfo->AuthenticationSecurityType;
  255. m_dwConcurrentSessions = pFeedInfo->ConcurrentSessions;
  256. m_fCreateAutomatically = pFeedInfo->AutoCreate;
  257. m_fEnabled = pFeedInfo->Enabled;
  258. m_mszDistributions = pFeedInfo->Distribution ? pFeedInfo->Distribution : _T("\0");
  259. if ( !FEED_IS_PULL (m_FeedType) ||
  260. (
  261. pFeedInfo->PullRequestTime.dwLowDateTime == 0 &&
  262. pFeedInfo->PullRequestTime.dwHighDateTime == 0
  263. )
  264. ) {
  265. //
  266. // Not a pull feed - so default to something reasonable here:
  267. //
  268. GetLocalTime ( &stPullNews );
  269. }
  270. else {
  271. FileTimeToLocalFileTime ( &pFeedInfo->PullRequestTime, &ftPullNewsLocal );
  272. FileTimeToSystemTime ( &ftPullNewsLocal, &stPullNews );
  273. }
  274. SystemTimeToVariantTime ( &stPullNews, &m_datePullNews );
  275. m_dwFeedInterval = pFeedInfo->FeedInterval;
  276. m_dwMaxConnectionAttempts = pFeedInfo->MaxConnectAttempts;
  277. m_mszNewsgroups = pFeedInfo->Newsgroups ? pFeedInfo->Newsgroups : _T("\0");
  278. m_dwSecurityType = pFeedInfo->SessionSecurityType;
  279. m_dwOutgoingPort = pFeedInfo->OutgoingPort;
  280. m_strUucpName = pFeedInfo->UucpName ? pFeedInfo->UucpName : _T("");
  281. m_strAccountName = pFeedInfo->NntpAccountName ? pFeedInfo->NntpAccountName : _T("");
  282. m_strPassword = pFeedInfo->NntpPassword ? pFeedInfo->NntpPassword : _T("");
  283. m_strTempDirectory = pFeedInfo->FeedTempDirectory;
  284. if ( pFeedInfo->Distribution ) {
  285. _ASSERT ( m_mszDistributions.SizeInBytes () == pFeedInfo->cbDistribution );
  286. }
  287. _ASSERT ( m_mszNewsgroups.SizeInBytes () == pFeedInfo->cbNewsgroups );
  288. m_strRemoteServer = pFeedInfo->ServerName ? pFeedInfo->ServerName : _T("");
  289. m_EnumType = FeedTypeToEnum ( m_FeedType );
  290. // Check Strings:
  291. if ( !CheckValid () ) {
  292. return E_OUTOFMEMORY;
  293. }
  294. return NOERROR;
  295. }
  296. HRESULT CFeed::ToFeedInfo ( LPNNTP_FEED_INFO pFeedInfo )
  297. {
  298. TraceFunctEnter ( "CFeed::ToFeedInfo" );
  299. AssertValid ();
  300. _ASSERT ( IS_VALID_OUT_PARAM ( pFeedInfo ) );
  301. HRESULT hr = NOERROR;
  302. SYSTEMTIME stPullNews;
  303. FILETIME ftPullNewsLocal;
  304. EnumToFeedType ( m_EnumType, m_FeedType );
  305. ZeroMemory ( pFeedInfo, sizeof (*pFeedInfo) );
  306. pFeedInfo->ServerName = m_strRemoteServer;
  307. pFeedInfo->FeedId = m_dwFeedId;
  308. pFeedInfo->FeedPairId = m_dwPairFeedId;
  309. pFeedInfo->FeedType = m_FeedType;
  310. pFeedInfo->fAllowControlMessages = m_fAllowControlMessages;
  311. pFeedInfo->AuthenticationSecurityType = m_dwAuthenticationType;
  312. pFeedInfo->ConcurrentSessions = m_dwConcurrentSessions;
  313. pFeedInfo->AutoCreate = m_fCreateAutomatically;
  314. pFeedInfo->Enabled = m_fEnabled;
  315. //
  316. // Convert time formats:
  317. //
  318. VariantTimeToSystemTime ( m_datePullNews, &stPullNews );
  319. SystemTimeToFileTime ( &stPullNews, &ftPullNewsLocal );
  320. LocalFileTimeToFileTime ( &ftPullNewsLocal, &pFeedInfo->PullRequestTime);
  321. ZeroMemory ( &pFeedInfo->StartTime, sizeof ( FILETIME ) );
  322. pFeedInfo->FeedInterval = m_dwFeedInterval;
  323. pFeedInfo->MaxConnectAttempts = m_dwMaxConnectionAttempts;
  324. pFeedInfo->SessionSecurityType = m_dwSecurityType;
  325. pFeedInfo->OutgoingPort = m_dwOutgoingPort;
  326. pFeedInfo->ServerName = m_strRemoteServer;
  327. pFeedInfo->UucpName = m_strUucpName;
  328. pFeedInfo->cbUucpName = STRING_BYTE_LENGTH ( m_strUucpName );
  329. pFeedInfo->NntpAccountName = m_strAccountName;
  330. pFeedInfo->cbAccountName = STRING_BYTE_LENGTH ( m_strAccountName );
  331. pFeedInfo->NntpPassword = m_strPassword;
  332. pFeedInfo->cbPassword = STRING_BYTE_LENGTH ( m_strPassword );
  333. pFeedInfo->FeedTempDirectory = m_strTempDirectory;
  334. pFeedInfo->cbFeedTempDirectory = STRING_BYTE_LENGTH ( m_strTempDirectory );
  335. pFeedInfo->Distribution = (LPWSTR) (LPCWSTR) m_mszDistributions;
  336. pFeedInfo->cbDistribution = m_mszDistributions.SizeInBytes();
  337. pFeedInfo->Newsgroups = (LPWSTR) (LPCWSTR) m_mszNewsgroups;
  338. pFeedInfo->cbNewsgroups = m_mszNewsgroups.SizeInBytes();
  339. TraceFunctLeave ();
  340. return hr;
  341. }
  342. HRESULT CFeed::FromINntpOneWayFeed ( INntpOneWayFeed * pFeed )
  343. {
  344. AssertValid ();
  345. CNntpOneWayFeed * pPrivateFeed;
  346. pPrivateFeed = (CNntpOneWayFeed *) pFeed;
  347. *this = pPrivateFeed->m_feed;
  348. if ( !CheckValid () ) {
  349. return E_OUTOFMEMORY;
  350. }
  351. return NOERROR;
  352. }
  353. HRESULT CFeed::ToINntpOneWayFeed ( INntpOneWayFeed ** ppFeed )
  354. {
  355. AssertValid ();
  356. HRESULT hr = NOERROR;
  357. CComObject<CNntpOneWayFeed> * pFeed = NULL;
  358. hr = CComObject<CNntpOneWayFeed>::CreateInstance ( &pFeed );
  359. if ( FAILED(hr) ) {
  360. goto Exit;
  361. }
  362. pFeed->m_feed = *this;
  363. if ( !pFeed->m_feed.CheckValid() ) {
  364. hr = E_OUTOFMEMORY;
  365. goto Exit;
  366. }
  367. hr = pFeed->QueryInterface ( IID_INntpOneWayFeed, (void **) ppFeed );
  368. if ( FAILED(hr) ) {
  369. goto Exit;
  370. }
  371. Exit:
  372. if ( FAILED(hr) ) {
  373. delete pFeed;
  374. }
  375. return hr;
  376. }
  377. HRESULT CFeed::CheckConfirm( IN DWORD dwFeedId,
  378. IN DWORD dwInstanceId,
  379. IN CMetabaseKey* pMK,
  380. OUT PDWORD pdwErr,
  381. OUT PDWORD pdwErrMask )
  382. {
  383. TraceFunctEnter( "CFeed::CheckConfirm" );
  384. _ASSERT( pMK );
  385. _ASSERT( dwFeedId > 0 );
  386. HRESULT hr;
  387. const DWORD dwMaxAttempts = 10;
  388. const DWORD dwWaitMilliSeconds = 500;
  389. DWORD dwHandShake;
  390. for ( int i = 0; i < dwMaxAttempts; i++ ) {
  391. hr = OpenKey( dwFeedId, pMK, METADATA_PERMISSION_READ, dwInstanceId );
  392. if ( FAILED( hr ) ) {
  393. if ( HRESULTTOWIN32( hr ) == ERROR_PATH_BUSY ) {
  394. Sleep( dwWaitMilliSeconds );
  395. continue;
  396. }
  397. else {
  398. ErrorTrace(0, "Open key fail with 0x%x", hr );
  399. return hr;
  400. }
  401. }
  402. //
  403. // getting the handshake
  404. //
  405. hr = pMK->GetDword( MD_FEED_HANDSHAKE, &dwHandShake );
  406. if ( FAILED( hr ) ) { // shouldn't happen , it's an error
  407. pMK->Close();
  408. ErrorTrace(0, "Get handshake fail with 0x%x", hr );
  409. return hr;
  410. }
  411. if ( dwHandShake != FEED_UPDATE_CONFIRM ) {
  412. pMK->Close();
  413. Sleep( dwWaitMilliSeconds );
  414. continue;
  415. }
  416. //
  417. // Now get error / masks
  418. //
  419. hr = pMK->GetDword( MD_FEED_ADMIN_ERROR, pdwErr );
  420. if ( FAILED( hr ) ) { // the server is possibly not
  421. // writing the confirm /error
  422. // in good sequence, lets give
  423. // it more chances
  424. pMK->Close();
  425. Sleep( dwWaitMilliSeconds );
  426. continue;
  427. }
  428. hr = pMK->GetDword( MD_FEED_ERR_PARM_MASK, pdwErrMask );
  429. if ( FAILED( hr ) ) { // same comments as above
  430. pMK->Close();
  431. Sleep( dwWaitMilliSeconds );
  432. continue;
  433. }
  434. //
  435. // Now we are done
  436. //
  437. pMK->Close();
  438. break;
  439. }
  440. if ( i == dwMaxAttempts ) return E_FAIL;
  441. else return S_OK;
  442. }
  443. HRESULT CFeed::Add ( LPCWSTR strServer, DWORD dwInstance, CMetabaseKey* pMK )
  444. {
  445. TraceFunctEnter ( "CFeed::Add" );
  446. AssertValid ();
  447. HRESULT hr = NOERROR;
  448. DWORD dwError = NOERROR;
  449. DWORD dwParmErr = 0;
  450. NNTP_FEED_INFO feedinfo;
  451. DWORD dwFeedId = 0;
  452. FillMemory ( &feedinfo, sizeof (feedinfo), 0 );
  453. hr = ToFeedInfo ( &feedinfo );
  454. if ( FAILED(hr) ) {
  455. goto Exit;
  456. }
  457. feedinfo.FeedId = 0;
  458. //
  459. // KangYan: RPC goes away. We use metabase writes
  460. //
  461. hr = AddFeedToMB( &feedinfo, pMK, &dwParmErr, dwInstance, &dwFeedId );
  462. if ( FAILED( hr ) ) {
  463. ErrorTrace(0, "Add to MB fail with 0x%x", hr );
  464. goto Exit;
  465. }
  466. hr = CheckConfirm( dwFeedId, dwInstance, pMK, &dwError, &dwParmErr );
  467. if ( FAILED( hr ) ) {
  468. ErrorTrace( 0, "Check confirm fail with 0x%x", hr );
  469. goto Exit;
  470. }
  471. if ( dwError != NOERROR ) {
  472. ErrorTraceX ( (LPARAM) this, "Failed to add feed: %x (%x)", dwError, dwParmErr );
  473. hr = TranslateFeedError ( dwError, dwParmErr );
  474. goto Exit;
  475. }
  476. this->m_dwFeedId = dwFeedId;
  477. Exit:
  478. TraceFunctLeave ();
  479. return hr;
  480. }
  481. HRESULT CFeed::Set ( LPCWSTR strServer, DWORD dwInstance, CMetabaseKey* pMK )
  482. {
  483. TraceFunctEnter ( "CFeed::Set" );
  484. AssertValid ();
  485. HRESULT hr = NOERROR;
  486. DWORD dwError = NOERROR;
  487. DWORD dwParmErr = 0;
  488. NNTP_FEED_INFO feedinfo;
  489. FillMemory ( &feedinfo, sizeof (feedinfo), 0 );
  490. hr = ToFeedInfo ( &feedinfo );
  491. if ( FAILED(hr) ) {
  492. goto Exit;
  493. }
  494. //
  495. // KangYan: RPC goes away. We use metabase writes
  496. //
  497. hr = SetFeedToMB( &feedinfo,
  498. pMK,
  499. &dwParmErr,
  500. dwInstance );
  501. if ( FAILED( hr ) ) {
  502. ErrorTrace(0, "Set MB fail with 0x%x", hr );
  503. goto Exit;
  504. }
  505. hr = CheckConfirm( feedinfo.FeedId, dwInstance, pMK, &dwError, &dwParmErr );
  506. if ( FAILED( hr ) ) {
  507. ErrorTrace(0, "Check confirm fail with 0x%x", hr );
  508. goto Exit;
  509. }
  510. if ( dwError != NOERROR ) {
  511. ErrorTraceX ( (LPARAM) this, "Failed to set feed[%d]: %x (%x)", m_dwFeedId, dwError, dwParmErr );
  512. hr = TranslateFeedError ( dwError, dwParmErr );
  513. goto Exit;
  514. }
  515. Exit:
  516. TraceFunctLeave ();
  517. return hr;
  518. }
  519. HRESULT CFeed::Remove ( LPCWSTR strServer, DWORD dwInstance, CMetabaseKey* pMK )
  520. {
  521. TraceFunctEnter ( "CFeed::Remove" );
  522. AssertValid ();
  523. HRESULT hr = NOERROR;
  524. DWORD dwError = NOERROR;
  525. hr = DeleteFeed( m_dwFeedId, pMK, dwInstance );
  526. if ( FAILED( hr ) ) {
  527. dwError = HRESULTTOWIN32( hr );
  528. ErrorTraceX ( (LPARAM) this, "Failed to remove feed[%d]: %x", m_dwFeedId, hr );
  529. hr = TranslateFeedError ( dwError );
  530. goto Exit;
  531. }
  532. Exit:
  533. TraceFunctLeave ();
  534. return hr;
  535. }
  536. HRESULT CFeed::SetPairId ( LPCWSTR strServer, DWORD dwInstance, DWORD dwPairId, CMetabaseKey* pMK )
  537. {
  538. TraceFunctEnter ( "CFeed::SetPairID" );
  539. AssertValid ();
  540. HRESULT hr = NOERROR;
  541. DWORD dwError = NOERROR;
  542. DWORD dwParmErr = 0;
  543. NNTP_FEED_INFO feedinfo;
  544. //
  545. // Assume that this feed was just Added/Set to the server.
  546. //
  547. _ASSERT ( dwPairId != m_dwFeedId );
  548. m_dwPairFeedId = dwPairId;
  549. FillMemory ( &feedinfo, sizeof (feedinfo), 0 );
  550. hr = ToFeedInfo ( &feedinfo );
  551. if ( FAILED(hr) ) {
  552. goto Exit;
  553. }
  554. //
  555. // KangYan: RPC goes away. We use metabase writes
  556. //
  557. hr = SetFeedToMB( &feedinfo,
  558. pMK,
  559. &dwParmErr,
  560. dwInstance );
  561. if ( FAILED( hr ) ) {
  562. ErrorTrace(0, "Set MB fail with 0x%x", hr );
  563. goto Exit;
  564. }
  565. hr = CheckConfirm( feedinfo.FeedId, dwInstance, pMK, &dwError, &dwParmErr );
  566. if ( FAILED( hr ) ) {
  567. ErrorTrace(0, "Check confirm fail with 0x%x", hr );
  568. goto Exit;
  569. }
  570. if ( dwError != NOERROR ) {
  571. ErrorTraceX ( (LPARAM) this, "Failed to set feed[%d]: %x (%x)", m_dwFeedId, dwError, dwParmErr );
  572. hr = TranslateFeedError ( dwError, dwParmErr );
  573. goto Exit;
  574. }
  575. Exit:
  576. TraceFunctLeave ();
  577. return hr;
  578. }
  579. DWORD GetBitPosition ( DWORD dwValue )
  580. {
  581. _ASSERT ( dwValue != 0 );
  582. // _ASSERT ( Only one bit should be on );
  583. DWORD dwResult;
  584. DWORD dwTemp;
  585. for ( dwTemp = dwValue, dwResult = (DWORD) -1;
  586. dwTemp != 0;
  587. dwTemp = dwTemp >> 1, dwResult++ ) {
  588. // Empty for
  589. // Make sure there is at most one bit on:
  590. _ASSERT ( !(dwTemp & 1) || dwTemp == 1 );
  591. }
  592. return dwResult;
  593. }
  594. HRESULT CFeed::TranslateFeedError ( DWORD dwErrorCode, DWORD dwParmErr )
  595. {
  596. HRESULT hr;
  597. _ASSERT ( dwErrorCode != NOERROR );
  598. if ( dwErrorCode != ERROR_INVALID_PARAMETER ||
  599. dwParmErr == 0 ||
  600. dwParmErr == (DWORD) -1
  601. ) {
  602. hr = RETURNCODETOHRESULT ( dwErrorCode );
  603. }
  604. else {
  605. DWORD dwBitPosition;
  606. DWORD nID;
  607. dwBitPosition = GetBitPosition ( dwParmErr );
  608. nID = IDS_FEED_PARM_ERR_BASE + dwBitPosition;
  609. hr = NntpCreateException ( nID );
  610. }
  611. return hr;
  612. }
  613. #ifdef DEBUG
  614. void CFeed::AssertValid ( ) const
  615. {
  616. _ASSERT ( !IsBadWritePtr ( (void *) this, sizeof (*this) ) );
  617. //
  618. // !!!magnush - Add more debug code here
  619. //
  620. }
  621. #endif
  622. /////////////////////////////////////////////////////////////////////
  623. //
  624. // CFeedPair Implementation
  625. //
  626. CFeedPair::CFeedPair () :
  627. m_type ( NNTP_FEED_TYPE_PEER ),
  628. m_pInbound ( NULL ),
  629. m_pOutbound ( NULL ),
  630. m_pNext ( NULL )
  631. {
  632. }
  633. CFeedPair::~CFeedPair ()
  634. {
  635. AssertValid ();
  636. Destroy ();
  637. }
  638. void CFeedPair::Destroy ()
  639. {
  640. AssertValid ();
  641. // !!!magnush - Fix reference counting problem here
  642. delete m_pInbound;
  643. delete m_pOutbound;
  644. m_pInbound = NULL;
  645. m_pOutbound = NULL;
  646. }
  647. HRESULT CFeedPair::CreateFeedPair (
  648. CFeedPair ** ppNewFeedPair,
  649. BSTR strRemoteServer,
  650. NNTP_FEED_SERVER_TYPE type
  651. )
  652. {
  653. _ASSERT ( IS_VALID_STRING (strRemoteServer) );
  654. HRESULT hr = NOERROR;
  655. CFeedPair * pNewFeedPair;
  656. *ppNewFeedPair = NULL;
  657. // Allocate a new feed pair:
  658. pNewFeedPair = new CFeedPair;
  659. if ( pNewFeedPair == NULL ) {
  660. BAIL_WITH_FAILURE ( hr, E_OUTOFMEMORY );
  661. }
  662. // Copy properties:
  663. pNewFeedPair->m_strRemoteServer = strRemoteServer;
  664. pNewFeedPair->m_type = type;
  665. // Check for failed copy:
  666. if ( pNewFeedPair->m_strRemoteServer == NULL ) {
  667. BAIL_WITH_FAILURE ( hr, E_OUTOFMEMORY );
  668. }
  669. // Set the out parameter to the new feed:
  670. *ppNewFeedPair = pNewFeedPair;
  671. Exit:
  672. if ( FAILED(hr) ) {
  673. delete pNewFeedPair;
  674. }
  675. return hr;
  676. }
  677. HRESULT CFeedPair::AddFeed ( CFeed * pFeed )
  678. {
  679. AssertValid ();
  680. HRESULT hr = NOERROR;
  681. _ASSERT ( IS_VALID_STRING ( m_strRemoteServer ) );
  682. _ASSERT ( IS_VALID_STRING ( pFeed->m_strRemoteServer ) );
  683. //
  684. // Check error conditions:
  685. // 1. Different remote server name
  686. // 2. Different feed type
  687. // 3. Two inbound feeds
  688. // 4. Two outbound feeds
  689. // 5. Bad feed type
  690. //
  691. if ( lstrcmpi ( m_strRemoteServer, pFeed->m_strRemoteServer ) != 0 ) {
  692. BAIL_WITH_FAILURE ( hr, E_FAIL );
  693. }
  694. if ( m_type != pFeed->m_EnumType ) {
  695. BAIL_WITH_FAILURE ( hr, E_FAIL );
  696. }
  697. if ( IsInboundFeed ( pFeed ) && m_pInbound != NULL ) {
  698. BAIL_WITH_FAILURE ( hr, E_FAIL );
  699. }
  700. if ( IsOutboundFeed ( pFeed ) && m_pOutbound != NULL ) {
  701. BAIL_WITH_FAILURE ( hr, E_FAIL );
  702. }
  703. if ( !IsInboundFeed ( pFeed ) && !IsOutboundFeed ( pFeed ) ) {
  704. _ASSERT (FALSE);
  705. BAIL_WITH_FAILURE ( hr, E_FAIL );
  706. }
  707. //
  708. // Everything is okay so take the feed into this pair:
  709. //
  710. if ( IsInboundFeed ( pFeed ) ) {
  711. m_pInbound = pFeed;
  712. }
  713. else {
  714. // It's an outbound feed:
  715. m_pOutbound = pFeed;
  716. }
  717. Exit:
  718. return hr;
  719. }
  720. HRESULT CFeedPair::FromINntpFeed ( INntpFeed * pFeed )
  721. {
  722. AssertValid ();
  723. HRESULT hr = NOERROR;
  724. CComPtr<INntpOneWayFeed> pInbound;
  725. CComPtr<INntpOneWayFeed> pOutbound;
  726. CFeed * pFeedInbound = NULL;
  727. CFeed * pFeedOutbound = NULL;
  728. m_strRemoteServer.Empty();
  729. pFeed->get_RemoteServer ( &m_strRemoteServer );
  730. pFeed->get_FeedType ( &m_type );
  731. pFeed->get_InboundFeed ( &pInbound );
  732. pFeed->get_OutboundFeed ( &pOutbound );
  733. if ( pInbound ) {
  734. hr = CFeed::CreateFeedFromINntpOneWayFeed ( pInbound, &pFeedInbound );
  735. BAIL_ON_FAILURE(hr);
  736. pFeedInbound->m_strRemoteServer = m_strRemoteServer;
  737. }
  738. if ( pOutbound ) {
  739. hr = CFeed::CreateFeedFromINntpOneWayFeed ( pOutbound, &pFeedOutbound );
  740. BAIL_ON_FAILURE(hr);
  741. pFeedOutbound->m_strRemoteServer = m_strRemoteServer;
  742. }
  743. delete m_pInbound;
  744. delete m_pOutbound;
  745. m_pInbound = pFeedInbound;
  746. m_pOutbound = pFeedOutbound;
  747. Exit:
  748. if ( FAILED(hr) ) {
  749. delete pFeedInbound;
  750. delete pFeedOutbound;
  751. }
  752. return hr;
  753. }
  754. HRESULT CFeedPair::ToINntpFeed ( INntpFeed ** ppFeed )
  755. {
  756. AssertValid ();
  757. CComObject<CNntpFeed> * pFeed = NULL;
  758. HRESULT hr = NOERROR;
  759. hr = CComObject<CNntpFeed>::CreateInstance ( &pFeed );
  760. if ( FAILED(hr) ) {
  761. goto Exit;
  762. }
  763. hr = pFeed->FromFeedPair ( this );
  764. if ( FAILED(hr) ) {
  765. goto Exit;
  766. }
  767. hr = pFeed->QueryInterface ( IID_INntpFeed, (void **) ppFeed );
  768. if ( FAILED(hr) ) {
  769. goto Exit;
  770. }
  771. Exit:
  772. return hr;
  773. }
  774. HRESULT CFeedPair::AddIndividualFeed ( LPCWSTR strServer,
  775. DWORD dwInstance,
  776. CFeed * pFeed ,
  777. CMetabaseKey* pMK )
  778. {
  779. AssertValid ();
  780. pFeed->m_dwPairFeedId = 0;
  781. pFeed->m_EnumType = m_type;
  782. pFeed->m_strRemoteServer = m_strRemoteServer;
  783. return pFeed->Add ( strServer, dwInstance, pMK );
  784. }
  785. HRESULT CFeedPair::SetIndividualFeed ( LPCWSTR strServer, DWORD dwInstance, CFeed * pFeed, CMetabaseKey* pMK )
  786. {
  787. AssertValid ();
  788. pFeed->m_dwPairFeedId = 0;
  789. pFeed->m_EnumType = m_type;
  790. pFeed->m_strRemoteServer = m_strRemoteServer;
  791. return pFeed->Set ( strServer, dwInstance, pMK );
  792. }
  793. HRESULT CFeedPair::SetPairIds ( LPCWSTR strServer, DWORD dwInstance,
  794. CFeed * pFeed1, CFeed * pFeed2, CMetabaseKey* pMK )
  795. {
  796. AssertValid ();
  797. HRESULT hr = NOERROR;
  798. DWORD dwPairId1;
  799. DWORD dwPairId2;
  800. dwPairId1 = pFeed2 ? pFeed2->m_dwFeedId : 0;
  801. dwPairId2 = pFeed1 ? pFeed1->m_dwFeedId : 0;
  802. if ( pFeed1 ) {
  803. hr = pFeed1->SetPairId ( strServer, dwInstance, dwPairId1, pMK );
  804. BAIL_ON_FAILURE(hr);
  805. }
  806. if ( pFeed2 ) {
  807. hr = pFeed2->SetPairId ( strServer, dwInstance, dwPairId2, pMK );
  808. BAIL_ON_FAILURE(hr);
  809. }
  810. Exit:
  811. return hr;
  812. }
  813. HRESULT CFeedPair::AddToServer ( LPCWSTR strServer, DWORD dwInstance, CMetabaseKey* pMK )
  814. {
  815. AssertValid ();
  816. HRESULT hr = E_UNEXPECTED;
  817. if ( m_pInbound ) {
  818. hr = AddIndividualFeed ( strServer, dwInstance, m_pInbound, pMK );
  819. BAIL_ON_FAILURE(hr);
  820. }
  821. if ( m_pOutbound ) {
  822. hr = AddIndividualFeed ( strServer, dwInstance, m_pOutbound, pMK );
  823. BAIL_ON_FAILURE(hr);
  824. }
  825. if ( m_pInbound && m_pOutbound ) {
  826. HRESULT hr2;
  827. hr2 = SetPairIds ( strServer, dwInstance, m_pInbound, m_pOutbound, pMK );
  828. _ASSERT ( SUCCEEDED(hr2) );
  829. }
  830. Exit:
  831. if ( FAILED(hr) ) {
  832. //
  833. // Undo the add:
  834. //
  835. IErrorInfo *pErrorInfo = NULL;
  836. if (FAILED(GetErrorInfo(NULL, &pErrorInfo))) {
  837. pErrorInfo = NULL;
  838. }
  839. if ( m_pInbound ) {
  840. m_pInbound->Remove ( strServer, dwInstance, pMK );
  841. }
  842. if ( m_pOutbound ) {
  843. m_pOutbound->Remove ( strServer, dwInstance, pMK );
  844. }
  845. if (pErrorInfo != NULL) {
  846. SetErrorInfo(NULL, pErrorInfo);
  847. }
  848. }
  849. return hr;
  850. }
  851. HRESULT CFeedPair::UndoFeedAction (
  852. LPCWSTR strServer,
  853. DWORD dwInstance,
  854. CFeed * pNewFeed,
  855. CFeed * pOldFeed,
  856. CMetabaseKey* pMK
  857. )
  858. {
  859. AssertValid ();
  860. HRESULT hr = NOERROR;
  861. if ( pNewFeed != NULL ) {
  862. if ( pOldFeed ) {
  863. hr = pOldFeed->Set ( strServer, dwInstance, pMK );
  864. }
  865. else {
  866. hr = pNewFeed->Remove ( strServer, dwInstance, pMK );
  867. }
  868. }
  869. return hr;
  870. }
  871. HRESULT CFeedPair::SetToServer ( LPCWSTR strServer, DWORD dwInstance, INntpFeed * pFeed, CMetabaseKey* pMK )
  872. {
  873. AssertValid ();
  874. HRESULT hr = NOERROR;
  875. CComPtr<INntpOneWayFeed> pInbound;
  876. CComPtr<INntpOneWayFeed> pOutbound;
  877. CFeed * pNewInbound = NULL;
  878. CFeed * pNewOutbound = NULL;
  879. CComBSTR strOldRemoteServer;
  880. strOldRemoteServer = m_strRemoteServer;
  881. pFeed->get_RemoteServer ( &m_strRemoteServer );
  882. pFeed->get_InboundFeed ( &pInbound );
  883. pFeed->get_OutboundFeed ( &pOutbound );
  884. //
  885. // Add the new feeds:
  886. //
  887. if ( !m_pInbound && pInbound ) {
  888. hr = CFeed::CreateFeedFromINntpOneWayFeed ( pInbound, &pNewInbound );
  889. BAIL_ON_FAILURE(hr);
  890. hr = AddIndividualFeed ( strServer, dwInstance, pNewInbound, pMK );
  891. BAIL_ON_FAILURE(hr);
  892. }
  893. if ( !m_pOutbound && pOutbound ) {
  894. hr = CFeed::CreateFeedFromINntpOneWayFeed ( pOutbound, &pNewOutbound );
  895. BAIL_ON_FAILURE(hr);
  896. hr = AddIndividualFeed ( strServer, dwInstance, pNewOutbound, pMK );
  897. BAIL_ON_FAILURE(hr);
  898. }
  899. //
  900. // Set the existing feeds:
  901. //
  902. if ( m_pInbound && pInbound ) {
  903. // The Inbound feed exists already, so call set on it:
  904. hr = CFeed::CreateFeed ( &pNewInbound );
  905. BAIL_ON_FAILURE(hr);
  906. *pNewInbound = *m_pInbound;
  907. hr = pNewInbound->FromINntpOneWayFeed ( pInbound );
  908. BAIL_ON_FAILURE(hr);
  909. hr = SetIndividualFeed ( strServer, dwInstance, pNewInbound, pMK );
  910. BAIL_ON_FAILURE(hr);
  911. }
  912. if ( m_pOutbound && pOutbound ) {
  913. // The Outbound feed exists already, so call set on it:
  914. hr = CFeed::CreateFeed ( &pNewOutbound );
  915. BAIL_ON_FAILURE(hr);
  916. *pNewOutbound = *m_pOutbound;
  917. hr = pNewOutbound->FromINntpOneWayFeed ( pOutbound );
  918. BAIL_ON_FAILURE(hr);
  919. hr = SetIndividualFeed ( strServer, dwInstance, pNewOutbound, pMK );
  920. BAIL_ON_FAILURE(hr);
  921. }
  922. //
  923. // Remove the deleted feeds:
  924. //
  925. if ( m_pInbound && !pInbound ) {
  926. HRESULT hr2;
  927. hr2 = m_pInbound->Remove ( strServer, dwInstance, pMK );
  928. _ASSERT ( SUCCEEDED(hr2) );
  929. }
  930. if ( m_pOutbound && !pOutbound ) {
  931. HRESULT hr2;
  932. hr2 = m_pOutbound->Remove ( strServer, dwInstance, pMK );
  933. _ASSERT ( SUCCEEDED(hr2) );
  934. }
  935. SetPairIds ( strServer, dwInstance, pNewInbound, pNewOutbound, pMK );
  936. _ASSERT ( SUCCEEDED(hr) );
  937. delete m_pInbound;
  938. delete m_pOutbound;
  939. m_pInbound = pNewInbound;
  940. m_pOutbound = pNewOutbound;
  941. Exit:
  942. if ( FAILED(hr) ) {
  943. //
  944. // Attempt to back out the changes:
  945. //
  946. UndoFeedAction ( strServer, dwInstance, pNewInbound, m_pInbound, pMK );
  947. UndoFeedAction ( strServer, dwInstance, pNewOutbound, m_pOutbound, pMK );
  948. if ( pNewOutbound ) {
  949. if ( m_pOutbound ) {
  950. m_pOutbound->Set ( strServer, dwInstance, pMK );
  951. }
  952. else {
  953. pNewOutbound->Remove ( strServer, dwInstance, pMK );
  954. }
  955. }
  956. delete pNewInbound;
  957. delete pNewOutbound;
  958. m_strRemoteServer = strOldRemoteServer;
  959. }
  960. return hr;
  961. }
  962. HRESULT CFeedPair::RemoveFromServer ( LPCWSTR strServer, DWORD dwInstance, CMetabaseKey* pMK )
  963. {
  964. AssertValid ();
  965. HRESULT hr = NOERROR;
  966. if ( m_pInbound ) {
  967. hr = m_pInbound->Remove ( strServer, dwInstance, pMK );
  968. }
  969. if ( m_pOutbound ) {
  970. hr = m_pOutbound->Remove ( strServer, dwInstance, pMK );
  971. }
  972. return hr;
  973. }
  974. BOOL CFeedPair::ContainsFeedId ( DWORD dwFeedId )
  975. {
  976. AssertValid ();
  977. if ( m_pInbound && m_pInbound->m_dwFeedId == dwFeedId ) {
  978. return TRUE;
  979. }
  980. if ( m_pOutbound && m_pOutbound->m_dwFeedId == dwFeedId ) {
  981. return TRUE;
  982. }
  983. return FALSE;
  984. }
  985. #ifdef DEBUG
  986. void CFeedPair::AssertValid ( ) const
  987. {
  988. _ASSERT ( !IsBadWritePtr ( (void *) this, sizeof (*this) ) );
  989. if ( m_pInbound ) {
  990. m_pInbound->AssertValid ();
  991. }
  992. if ( m_pOutbound ) {
  993. m_pOutbound->AssertValid ();
  994. }
  995. }
  996. #endif
  997. /////////////////////////////////////////////////////////////////////
  998. //
  999. // CFeedPairList Implementation
  1000. //
  1001. CFeedPairList::CFeedPairList () :
  1002. m_cCount ( 0 ),
  1003. m_pHead ( NULL ),
  1004. m_pTail ( NULL )
  1005. {
  1006. }
  1007. CFeedPairList::~CFeedPairList ()
  1008. {
  1009. AssertValid ();
  1010. Empty();
  1011. }
  1012. DWORD CFeedPairList::GetCount ( ) const
  1013. {
  1014. AssertValid ();
  1015. return m_cCount;
  1016. }
  1017. void CFeedPairList::Empty ( )
  1018. {
  1019. AssertValid ();
  1020. CFeedPair * pPair;
  1021. CFeedPair * pKill;
  1022. pPair = m_pHead;
  1023. while ( pPair ) {
  1024. pKill = pPair;
  1025. pPair = pPair->m_pNext;
  1026. delete pKill;
  1027. }
  1028. m_cCount = 0;
  1029. m_pHead = NULL;
  1030. m_pTail = NULL;
  1031. }
  1032. CFeedPair * CFeedPairList::Item ( DWORD index )
  1033. {
  1034. AssertValid ();
  1035. CFeedPair * pResult = NULL;
  1036. DWORD i;
  1037. if ( index >= m_cCount ) {
  1038. return NULL;
  1039. }
  1040. pResult = m_pHead;
  1041. _ASSERT ( pResult );
  1042. for ( i = 0; i < index; i++ ) {
  1043. pResult = pResult->m_pNext;
  1044. _ASSERT ( pResult );
  1045. }
  1046. return pResult;
  1047. }
  1048. void CFeedPairList::Add ( CFeedPair * pFeedPair )
  1049. {
  1050. AssertValid ();
  1051. _ASSERT ( GetPairIndex ( pFeedPair ) == (DWORD) -1 );
  1052. pFeedPair->m_pNext = NULL;
  1053. if ( m_pTail == NULL ) {
  1054. //
  1055. // Handle special case - Adding to empty list:
  1056. //
  1057. _ASSERT ( m_pHead == NULL );
  1058. m_pHead = pFeedPair;
  1059. m_pTail = pFeedPair;
  1060. }
  1061. else {
  1062. m_pTail->m_pNext = pFeedPair;
  1063. m_pTail = pFeedPair;
  1064. }
  1065. m_cCount++;
  1066. }
  1067. void CFeedPairList::Remove ( CFeedPair * pFeedPair )
  1068. {
  1069. AssertValid ();
  1070. _ASSERT ( GetPairIndex ( pFeedPair ) != (DWORD) -1 );
  1071. CFeedPair * pLead;
  1072. CFeedPair * pFollow;
  1073. for ( pLead = m_pHead, pFollow = NULL;
  1074. pLead != NULL && pLead != pFeedPair;
  1075. pFollow = pLead, pLead = pLead->m_pNext
  1076. ) {
  1077. // Empty For
  1078. }
  1079. _ASSERT ( pLead );
  1080. if ( !pLead ) {
  1081. return;
  1082. }
  1083. if ( pFollow != NULL ) {
  1084. pFollow->m_pNext = pLead->m_pNext;
  1085. }
  1086. if ( m_pHead == pFeedPair ) {
  1087. m_pHead = m_pHead->m_pNext;
  1088. }
  1089. if ( m_pTail == pFeedPair ) {
  1090. m_pTail = pFollow;
  1091. }
  1092. delete pFeedPair;
  1093. m_cCount--;
  1094. }
  1095. CFeedPair * CFeedPairList::Find ( DWORD dwFeedId )
  1096. {
  1097. AssertValid ();
  1098. CFeedPair * pResult;
  1099. if ( dwFeedId == 0 ) {
  1100. return NULL;
  1101. }
  1102. for ( pResult = m_pHead; pResult != NULL; pResult = pResult->m_pNext ) {
  1103. if ( pResult->ContainsFeedId ( dwFeedId ) ) {
  1104. return pResult;
  1105. }
  1106. }
  1107. return NULL;
  1108. }
  1109. DWORD CFeedPairList::GetPairIndex ( CFeedPair * pPairToFind ) const
  1110. {
  1111. AssertValid ();
  1112. _ASSERT ( pPairToFind );
  1113. DWORD index;
  1114. CFeedPair * pFeedPair;
  1115. for ( pFeedPair = m_pHead, index = 0;
  1116. pFeedPair != NULL;
  1117. pFeedPair = pFeedPair->m_pNext, index++ ) {
  1118. if ( pFeedPair == pPairToFind ) {
  1119. return index;
  1120. }
  1121. }
  1122. return (DWORD) -1;
  1123. }
  1124. #ifdef DEBUG
  1125. void CFeedPairList::AssertValid ( ) const
  1126. {
  1127. _ASSERT ( !IsBadWritePtr ( (void *) this, sizeof (*this) ) );
  1128. // Walk the list and assert each feed pair is valid:
  1129. CFeedPair * pPair;
  1130. DWORD cCount;
  1131. for ( cCount = 0, pPair = m_pHead;
  1132. pPair != NULL;
  1133. pPair = pPair->m_pNext, cCount++
  1134. ) {
  1135. _ASSERT ( !IsBadWritePtr ( pPair, sizeof (*pPair) ) );
  1136. _ASSERT ( IS_VALID_STRING ( pPair->m_strRemoteServer ) );
  1137. _ASSERT ( pPair->m_pInbound || pPair->m_pOutbound );
  1138. if ( pPair->m_pInbound ) {
  1139. _ASSERT ( IS_VALID_STRING ( pPair->m_pInbound->m_strRemoteServer ) );
  1140. _ASSERT ( !lstrcmpi ( pPair->m_pInbound->m_strRemoteServer, pPair->m_strRemoteServer ) );
  1141. }
  1142. if ( pPair->m_pOutbound ) {
  1143. _ASSERT ( IS_VALID_STRING ( pPair->m_pOutbound->m_strRemoteServer ) );
  1144. _ASSERT ( !lstrcmpi ( pPair->m_pOutbound->m_strRemoteServer, pPair->m_strRemoteServer ) );
  1145. }
  1146. }
  1147. _ASSERT ( m_cCount == cCount );
  1148. }
  1149. #endif