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.

639 lines
15 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name :
  4. pe_dispi.hxx
  5. Abstract:
  6. This module provides the implementation for the protocol
  7. event dispatchers
  8. Author:
  9. Keith Lau (KeithLau) 6/24/98
  10. Project:
  11. SMTP Server DLL
  12. Revision History:
  13. KeithLau Created
  14. --*/
  15. #ifndef _PE_DISPI_HXX_
  16. #define _PE_DISPI_HXX_
  17. #ifndef PRIO_LOW
  18. #define PRIO_LOW 24575
  19. #endif
  20. #ifndef PRIO_LOWEST
  21. #define PRIO_LOWEST 32767
  22. #endif
  23. #ifndef PRIO_DEFAULT
  24. #define PRIO_DEFAULT PRIO_LOW
  25. #endif
  26. //
  27. // Define a prime number for default hash sizes
  28. //
  29. #define PERE_HASH_SIZE 13
  30. //
  31. // Enumerated types for different event types
  32. //
  33. typedef enum _OUTBOUND_EVENT_TYPES
  34. {
  35. PE_OET_SESSION_START = 0,
  36. PE_OET_MESSAGE_START,
  37. PE_OET_PER_RECIPIENT,
  38. PE_OET_BEFORE_DATA,
  39. PE_OET_SESSION_END,
  40. PE_OET_INVALID_EVENT_TYPE
  41. } OUTBOUND_EVENT_TYPES;
  42. // =================================================================
  43. // Generic dispatcher routines
  44. //
  45. class CGenericProtoclEventDispatcher
  46. {
  47. public:
  48. static HRESULT GetLowerAnsiStringFromVariant(
  49. CComVariant &vString,
  50. LPSTR pszString,
  51. DWORD *pdwLength
  52. );
  53. static HRESULT InsertBinding(
  54. LPPE_COMMAND_NODE *ppHeadNode,
  55. LPPE_BINDING_NODE pBinding,
  56. LPSTR pszCommandKeyword,
  57. DWORD dwCommandKeywordSize
  58. );
  59. static HRESULT InsertBindingWithHash(
  60. LPPE_COMMAND_NODE *rgpHeadNodes,
  61. DWORD dwHashSize,
  62. LPPE_BINDING_NODE pBinding,
  63. LPSTR pszCommandKeyword,
  64. DWORD dwCommandKeywordSize
  65. );
  66. static HRESULT FindCommandFromHash(
  67. LPPE_COMMAND_NODE *rgpHeadNodes,
  68. DWORD dwHashSize,
  69. LPSTR pszCommandKeyword,
  70. DWORD dwCommandKeywordSize,
  71. LPPE_COMMAND_NODE *ppCommandNode
  72. );
  73. static DWORD GetHashValue(
  74. DWORD dwBuckets,
  75. LPSTR pszKey,
  76. DWORD dwKeySize
  77. )
  78. {
  79. DWORD dwHash = 0;
  80. if (dwKeySize > 3)
  81. dwKeySize = 3;
  82. while (dwKeySize--)
  83. dwHash ^= (DWORD)*pszKey++;
  84. return(dwHash % dwBuckets);
  85. }
  86. static HRESULT CleanupCommandNodes(
  87. LPPE_COMMAND_NODE pHeadNode,
  88. LPPE_COMMAND_NODE pSkipNode
  89. );
  90. };
  91. // =================================================================
  92. // Inbound command dispatcher
  93. //
  94. class CInboundDispatcher :
  95. public CEventBaseDispatcher,
  96. public CGenericProtoclEventDispatcher,
  97. public ISmtpInboundCommandDispatcher
  98. {
  99. public:
  100. CInboundDispatcher()
  101. {
  102. m_lRefCount = 0;
  103. m_fSinksInstalled = FALSE;
  104. // Initialize the hash
  105. m_dwHashSize = sizeof(m_rgpCommandList) / sizeof(LPPE_COMMAND_NODE);
  106. for (DWORD i = 0 ; i < m_dwHashSize; i++)
  107. m_rgpCommandList[i] = NULL;
  108. }
  109. ~CInboundDispatcher()
  110. {
  111. // Clean up any command nodes allocated
  112. for (DWORD i = 0 ; i < m_dwHashSize; i++)
  113. {
  114. _VERIFY(CGenericProtoclEventDispatcher::CleanupCommandNodes(
  115. m_rgpCommandList[i],
  116. NULL) == S_OK);
  117. }
  118. }
  119. HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID *ppvObj)
  120. {
  121. if (riid == IID_IUnknown)
  122. *ppvObj = (IUnknown *)(ISmtpInboundCommandDispatcher *)this;
  123. else if (riid == IID_ISmtpInboundCommandDispatcher)
  124. *ppvObj = (ISmtpInboundCommandDispatcher *)this;
  125. else if (riid == IID_IEventDispatcher)
  126. *ppvObj = (IEventDispatcher *)this;
  127. else
  128. return(E_NOINTERFACE);
  129. AddRef();
  130. return(S_OK);
  131. }
  132. unsigned long STDMETHODCALLTYPE AddRef()
  133. {
  134. return(InterlockedIncrement(&m_lRefCount));
  135. }
  136. unsigned long STDMETHODCALLTYPE Release()
  137. {
  138. LONG lTemp = InterlockedDecrement(&m_lRefCount);
  139. _ASSERT(lTemp >= 0);
  140. if (!lTemp)
  141. delete this;
  142. return(lTemp);
  143. }
  144. HRESULT STDMETHODCALLTYPE ChainSinks(
  145. IUnknown *pServer,
  146. IUnknown *pSession,
  147. IMailMsgProperties *pMsg,
  148. ISmtpInCommandContext *pContext,
  149. DWORD dwStopAtPriority,
  150. LPPE_COMMAND_NODE pCommandNode,
  151. LPPE_BINDING_NODE *ppResumeFrom
  152. );
  153. HRESULT STDMETHODCALLTYPE SinksInstalled(
  154. LPSTR szCommandKeyword,
  155. LPPE_COMMAND_NODE *ppCommandNode
  156. )
  157. {
  158. return(CGenericProtoclEventDispatcher::FindCommandFromHash(
  159. m_rgpCommandList,
  160. m_dwHashSize,
  161. szCommandKeyword,
  162. strlen(szCommandKeyword),
  163. ppCommandNode));
  164. }
  165. HRESULT AllocBinding(
  166. REFGUID rguidEventType,
  167. IEventBinding *piBinding,
  168. CBinding **ppNewBinding
  169. );
  170. //
  171. // Local binding class
  172. //
  173. class CInboundBinding :
  174. public CGenericProtoclEventDispatcher,
  175. public CEventBaseDispatcher::CBinding
  176. {
  177. public:
  178. CInboundBinding(
  179. CInboundDispatcher *pDispatcher
  180. )
  181. {
  182. _ASSERT(pDispatcher);
  183. m_pDispatcher = pDispatcher;
  184. }
  185. HRESULT Init(IEventBinding *piBinding);
  186. PE_BINDING_NODE m_bnInfo;
  187. CInboundDispatcher *m_pDispatcher;
  188. };
  189. public:
  190. LPPE_COMMAND_NODE m_rgpCommandList[PERE_HASH_SIZE];
  191. DWORD m_dwHashSize;
  192. BOOL m_fSinksInstalled;
  193. private:
  194. LONG m_lRefCount;
  195. };
  196. // =================================================================
  197. // Outbound command generation dispatcher
  198. //
  199. class COutboundDispatcher :
  200. public CEventBaseDispatcher,
  201. public CGenericProtoclEventDispatcher,
  202. public ISmtpOutboundCommandDispatcher
  203. {
  204. public:
  205. COutboundDispatcher()
  206. {
  207. m_lRefCount = 0;
  208. m_fSinksInstalled = FALSE;
  209. InitializeDefaultCommandBindings();
  210. }
  211. ~COutboundDispatcher()
  212. {
  213. // Clean up any command nodes allocated, make sure
  214. // we don't try to delete our default node
  215. for (DWORD i = 0; i < PE_STATE_MAX_STATES; i++)
  216. {
  217. _VERIFY(CGenericProtoclEventDispatcher::CleanupCommandNodes(
  218. m_rgpCommandList[i],
  219. &(m_rgcnDefaultCommand[i])) == S_OK);
  220. }
  221. }
  222. void InitializeDefaultCommandBindings();
  223. HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID *ppvObj)
  224. {
  225. if (riid == IID_IUnknown)
  226. *ppvObj = (IUnknown *)(ISmtpOutboundCommandDispatcher *)this;
  227. else if (riid == IID_ISmtpOutboundCommandDispatcher)
  228. *ppvObj = (ISmtpOutboundCommandDispatcher *)this;
  229. else if (riid == IID_IEventDispatcher)
  230. *ppvObj = (IEventDispatcher *)this;
  231. else
  232. return(E_NOINTERFACE);
  233. AddRef();
  234. return(S_OK);
  235. }
  236. unsigned long STDMETHODCALLTYPE AddRef()
  237. {
  238. return(InterlockedIncrement(&m_lRefCount));
  239. }
  240. unsigned long STDMETHODCALLTYPE Release()
  241. {
  242. LONG lTemp = InterlockedDecrement(&m_lRefCount);
  243. _ASSERT(lTemp >= 0);
  244. if (!lTemp)
  245. delete this;
  246. return(lTemp);
  247. }
  248. HRESULT STDMETHODCALLTYPE ChainSinks(
  249. IUnknown *pServer,
  250. IUnknown *pSession,
  251. IMailMsgProperties *pMsg,
  252. ISmtpOutCommandContext *pContext,
  253. DWORD dwEventType,
  254. LPPE_COMMAND_NODE *ppPreviousCommand,
  255. LPPE_BINDING_NODE *ppResumeFrom
  256. );
  257. HRESULT STDMETHODCALLTYPE SinksInstalled(
  258. DWORD dwEventType
  259. )
  260. {
  261. return((m_rgpCommandList[dwEventType] != NULL)?S_OK:S_FALSE);
  262. }
  263. HRESULT AllocBinding(
  264. REFGUID rguidEventType,
  265. IEventBinding *piBinding,
  266. CBinding **ppNewBinding
  267. );
  268. //
  269. // Local binding class
  270. //
  271. class COutboundBinding :
  272. public CGenericProtoclEventDispatcher,
  273. public CEventBaseDispatcher::CBinding
  274. {
  275. public:
  276. COutboundBinding(
  277. COutboundDispatcher *pDispatcher,
  278. REFGUID rguidEventType
  279. );
  280. HRESULT Init(IEventBinding *piBinding);
  281. DWORD m_dwEventType;
  282. PE_BINDING_NODE m_bnInfo;
  283. COutboundDispatcher *m_pDispatcher;
  284. };
  285. public:
  286. LPPE_COMMAND_NODE m_rgpCommandList[PE_STATE_MAX_STATES];
  287. BOOL m_fSinksInstalled;
  288. static const GUID *s_rgrguidEventTypes[PE_STATE_MAX_STATES];
  289. static char *s_rgszDefaultCommand[PE_STATE_MAX_STATES];
  290. private:
  291. LONG m_lRefCount;
  292. PE_COMMAND_NODE m_rgcnDefaultCommand[PE_STATE_MAX_STATES];
  293. PE_BINDING_NODE m_rgbnDefaultCommand[PE_STATE_MAX_STATES];
  294. };
  295. // =================================================================
  296. // Server response dispatcher
  297. //
  298. class CResponseDispatcher :
  299. public CEventBaseDispatcher,
  300. public CGenericProtoclEventDispatcher,
  301. public ISmtpServerResponseDispatcher
  302. {
  303. public:
  304. CResponseDispatcher()
  305. {
  306. m_lRefCount = 0;
  307. m_fSinksInstalled = FALSE;
  308. // Initialize the hash
  309. m_dwHashSize = sizeof(m_rgpCommandList) / sizeof(LPPE_COMMAND_NODE);
  310. for (DWORD i = 0 ; i < m_dwHashSize; i++)
  311. m_rgpCommandList[i] = NULL;
  312. }
  313. ~CResponseDispatcher()
  314. {
  315. // Clean up any command nodes allocated
  316. for (DWORD i = 0 ; i < m_dwHashSize; i++)
  317. {
  318. _VERIFY(CGenericProtoclEventDispatcher::CleanupCommandNodes(
  319. m_rgpCommandList[i],
  320. NULL) == S_OK);
  321. }
  322. }
  323. HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID *ppvObj)
  324. {
  325. if (riid == IID_IUnknown)
  326. *ppvObj = (IUnknown *)(ISmtpServerResponseDispatcher *)this;
  327. else if (riid == IID_ISmtpServerResponseDispatcher)
  328. *ppvObj = (ISmtpServerResponseDispatcher *)this;
  329. else if (riid == IID_IEventDispatcher)
  330. *ppvObj = (IEventDispatcher *)this;
  331. else
  332. return(E_NOINTERFACE);
  333. AddRef();
  334. return(S_OK);
  335. }
  336. unsigned long STDMETHODCALLTYPE AddRef()
  337. {
  338. return(InterlockedIncrement(&m_lRefCount));
  339. }
  340. unsigned long STDMETHODCALLTYPE Release()
  341. {
  342. LONG lTemp = InterlockedDecrement(&m_lRefCount);
  343. _ASSERT(lTemp >= 0);
  344. if (!lTemp)
  345. delete this;
  346. return(lTemp);
  347. }
  348. HRESULT STDMETHODCALLTYPE ChainSinks(
  349. IUnknown *pServer,
  350. IUnknown *pSession,
  351. IMailMsgProperties *pMsg,
  352. ISmtpServerResponseContext *pContext,
  353. DWORD dwStopAtPriority,
  354. LPPE_COMMAND_NODE pCommandNode,
  355. LPPE_BINDING_NODE *ppResumeFrom
  356. );
  357. HRESULT STDMETHODCALLTYPE SinksInstalled(
  358. LPSTR szCommandKeyword,
  359. LPPE_COMMAND_NODE *ppCommandNode
  360. )
  361. {
  362. return(CGenericProtoclEventDispatcher::FindCommandFromHash(
  363. m_rgpCommandList,
  364. m_dwHashSize,
  365. szCommandKeyword,
  366. strlen(szCommandKeyword),
  367. ppCommandNode));
  368. }
  369. HRESULT AllocBinding(
  370. REFGUID rguidEventType,
  371. IEventBinding *piBinding,
  372. CBinding **ppNewBinding
  373. );
  374. //
  375. // Local binding class
  376. //
  377. class CResponseBinding :
  378. public CGenericProtoclEventDispatcher,
  379. public CEventBaseDispatcher::CBinding
  380. {
  381. public:
  382. CResponseBinding(
  383. CResponseDispatcher *pDispatcher
  384. )
  385. {
  386. _ASSERT(pDispatcher);
  387. m_pDispatcher = pDispatcher;
  388. }
  389. HRESULT Init(IEventBinding *piBinding);
  390. PE_BINDING_NODE m_bnInfo;
  391. CResponseDispatcher *m_pDispatcher;
  392. };
  393. //
  394. // Map from our internal Protocol Event state to the value
  395. // published in smtpevent.idl
  396. //
  397. static PE_STATES PeStateFromOutboundEventType(
  398. OUTBOUND_EVENT_TYPES EventType)
  399. {
  400. switch(EventType) {
  401. case PE_OET_SESSION_START:
  402. return PE_STATE_SESSION_START;
  403. case PE_OET_MESSAGE_START:
  404. return PE_STATE_MESSAGE_START;
  405. case PE_OET_PER_RECIPIENT:
  406. return PE_STATE_PER_RECIPIENT;
  407. case PE_OET_BEFORE_DATA:
  408. return PE_STATE_DATA_OR_BDAT;
  409. case PE_OET_SESSION_END:
  410. return PE_STATE_SESSION_END;
  411. case PE_OET_INVALID_EVENT_TYPE:
  412. default:
  413. _ASSERT(0 && "Invalid event type");
  414. return PE_STATE_DEFAULT;
  415. }
  416. }
  417. public:
  418. LPPE_COMMAND_NODE m_rgpCommandList[PERE_HASH_SIZE];
  419. DWORD m_dwHashSize;
  420. BOOL m_fSinksInstalled;
  421. private:
  422. LONG m_lRefCount;
  423. };
  424. // =================================================================
  425. // Class factories
  426. //
  427. class CInboundDispatcherClassFactory :
  428. public IClassFactory
  429. {
  430. HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID *ppvObj)
  431. {
  432. _ASSERT(FALSE); return E_NOTIMPL;
  433. }
  434. unsigned long STDMETHODCALLTYPE AddRef () { _ASSERT(FALSE); return 0; }
  435. unsigned long STDMETHODCALLTYPE Release () { _ASSERT(FALSE); return 0; }
  436. HRESULT STDMETHODCALLTYPE CreateInstance (LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppvObj)
  437. {
  438. // The dispatcher cannot be part of an aggregate
  439. if (pUnkOuter)
  440. return(CLASS_E_NOAGGREGATION);
  441. if (!ppvObj)
  442. return(E_POINTER);
  443. *ppvObj = NULL;
  444. CInboundDispatcher *pDispatcher = new CInboundDispatcher();
  445. if (!pDispatcher)
  446. return(E_OUTOFMEMORY);
  447. // QI to give it the initial refcount
  448. HRESULT hrRes = pDispatcher->QueryInterface(riid, ppvObj);
  449. if (FAILED(hrRes))
  450. delete pDispatcher;
  451. else
  452. *ppvObj = (LPVOID)pDispatcher;
  453. return(hrRes);
  454. }
  455. HRESULT STDMETHODCALLTYPE LockServer (int fLock)
  456. {
  457. _ASSERT(FALSE); return E_NOTIMPL;
  458. }
  459. };
  460. class COutboundDispatcherClassFactory :
  461. public IClassFactory
  462. {
  463. HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID *ppvObj)
  464. {
  465. _ASSERT(FALSE); return E_NOTIMPL;
  466. }
  467. unsigned long STDMETHODCALLTYPE AddRef () { _ASSERT(FALSE); return 0; }
  468. unsigned long STDMETHODCALLTYPE Release () { _ASSERT(FALSE); return 0; }
  469. HRESULT STDMETHODCALLTYPE CreateInstance (LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppvObj)
  470. {
  471. // The dispatcher cannot be part of an aggregate
  472. if (pUnkOuter)
  473. return(CLASS_E_NOAGGREGATION);
  474. if (!ppvObj)
  475. return(E_POINTER);
  476. *ppvObj = NULL;
  477. COutboundDispatcher *pDispatcher = new COutboundDispatcher();
  478. if (!pDispatcher)
  479. return(E_OUTOFMEMORY);
  480. // QI to give it the initial refcount
  481. HRESULT hrRes = pDispatcher->QueryInterface(riid, ppvObj);
  482. if (FAILED(hrRes))
  483. delete pDispatcher;
  484. else
  485. *ppvObj = (LPVOID)pDispatcher;
  486. return(hrRes);
  487. }
  488. HRESULT STDMETHODCALLTYPE LockServer (int fLock)
  489. {
  490. _ASSERT(FALSE); return E_NOTIMPL;
  491. }
  492. };
  493. class CResponseDispatcherClassFactory :
  494. public IClassFactory
  495. {
  496. HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID *ppvObj)
  497. {
  498. _ASSERT(FALSE); return E_NOTIMPL;
  499. }
  500. unsigned long STDMETHODCALLTYPE AddRef () { _ASSERT(FALSE); return 0; }
  501. unsigned long STDMETHODCALLTYPE Release () { _ASSERT(FALSE); return 0; }
  502. HRESULT STDMETHODCALLTYPE CreateInstance (LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppvObj)
  503. {
  504. // The dispatcher cannot be part of an aggregate
  505. if (pUnkOuter)
  506. return(CLASS_E_NOAGGREGATION);
  507. if (!ppvObj)
  508. return(E_POINTER);
  509. *ppvObj = NULL;
  510. CResponseDispatcher *pDispatcher = new CResponseDispatcher();
  511. if (!pDispatcher)
  512. return(E_OUTOFMEMORY);
  513. // QI to give it the initial refcount
  514. HRESULT hrRes = pDispatcher->QueryInterface(riid, ppvObj);
  515. if (FAILED(hrRes))
  516. delete pDispatcher;
  517. else
  518. *ppvObj = (LPVOID)pDispatcher;
  519. return(hrRes);
  520. }
  521. HRESULT STDMETHODCALLTYPE LockServer (int fLock)
  522. {
  523. _ASSERT(FALSE); return E_NOTIMPL;
  524. }
  525. };
  526. //
  527. // External declaration of the dispatcher class factories
  528. //
  529. extern CInboundDispatcherClassFactory g_cfInbound;
  530. extern COutboundDispatcherClassFactory g_cfOutbound;
  531. extern CResponseDispatcherClassFactory g_cfResponse;
  532. #endif