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.

1399 lines
32 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. xplogon.cpp
  5. Abstract:
  6. This module contains the XPLOGON class implementation.
  7. Author:
  8. Wesley Witt (wesw) 13-Aug-1996
  9. --*/
  10. #include "faxxp.h"
  11. #include "debugex.h"
  12. #pragma hdrstop
  13. #include <mbstring.h>
  14. LPSTR gszFAXAddressType = FAX_ADDRESS_TYPE_A;
  15. LPSTR *gpszXPAddressTypes;
  16. LPSTR ConvertTStringToAString(LPCTSTR lpctstrSource);
  17. CXPLogon::CXPLogon(
  18. HINSTANCE hInstance,
  19. LPMAPISUP pSupObj,
  20. LPTSTR ProfileName
  21. )
  22. /*++
  23. Routine Description:
  24. Constructor of the object. Parameters are passed to initialize the
  25. data members with the appropiate values.
  26. Arguments:
  27. hInstance - Instance of the provider DLL
  28. pSupObj - Pointer to IMAPISupport object used in
  29. CXPLogon methods
  30. Return Value:
  31. None.
  32. --*/
  33. {
  34. DBG_ENTER(TEXT("CXPLogon::CXPLogon"));
  35. m_cRef = 1;
  36. m_hInstance = hInstance;
  37. m_pSupObj = pSupObj;
  38. m_fABWDSInstalled = FALSE;
  39. m_ulTransportStatus = 0;
  40. m_pSupObj->AddRef();
  41. }
  42. CXPLogon::~CXPLogon()
  43. /*++
  44. Routine Description:
  45. Destructor of CXPLogon. Releases memory allocated for internal
  46. properties during the life of this transport logon object.
  47. Arguments:
  48. None.
  49. Return Value:
  50. None.
  51. --*/
  52. {
  53. DBG_ENTER(TEXT("CXPLogon::~CXPLogon"));
  54. // Release the IMAPISupport object
  55. m_pSupObj->Release();
  56. m_pSupObj = NULL;
  57. }
  58. STDMETHODIMP
  59. CXPLogon::QueryInterface(
  60. REFIID riid,
  61. LPVOID * ppvObj
  62. )
  63. /*++
  64. Routine Description:
  65. Returns a pointer to a interface requested if the interface is
  66. supported and implemented by this object. If it is not supported, it
  67. returns NULL.
  68. Arguments:
  69. Refer to OLE Documentation on this method.
  70. Return Value:
  71. An HRESULT.
  72. --*/
  73. {
  74. // OLE requires NULLing parameter
  75. *ppvObj = NULL;
  76. // If this is one of the two IID return an interface pointer to it
  77. if (riid == IID_IXPLogon || riid == IID_IUnknown)
  78. {
  79. *ppvObj = (LPVOID)this;
  80. // Increase usage count of this object
  81. AddRef();
  82. return S_OK;
  83. }
  84. // This object does not support the interface requested
  85. return E_NOINTERFACE;
  86. }
  87. STDMETHODIMP
  88. CXPLogon::AddressTypes(
  89. ULONG * pulFlags,
  90. ULONG * pcAdrType,
  91. LPTSTR ** pppAdrTypeArray,
  92. ULONG * pcMAPIUID,
  93. LPMAPIUID ** pppMAPIUIDArray
  94. )
  95. /*++
  96. Routine Description:
  97. Called by the MAPI Spooler when initializing this XP logon object to
  98. allow the transport to register the address it will handle.
  99. Arguments:
  100. Refer to OLE Documentation on this method.
  101. Return Value:
  102. S_OK always
  103. --*/
  104. {
  105. HRESULT hr = S_OK;
  106. DBG_ENTER(TEXT("CXPLogon::AddressTypes"),hr);
  107. *pcAdrType = 1;
  108. *pulFlags = 0;
  109. gpszXPAddressTypes = &gszFAXAddressType;
  110. *pppAdrTypeArray = (LPTSTR*)gpszXPAddressTypes;
  111. *pcMAPIUID = 0;
  112. *pppMAPIUIDArray = NULL;
  113. return hr;
  114. }
  115. STDMETHODIMP
  116. CXPLogon::RegisterOptions(
  117. ULONG * pulFlags,
  118. ULONG * pcOptions,
  119. LPOPTIONDATA * ppOptions
  120. )
  121. /*++
  122. Routine Description:
  123. This transport does not registers any per-recipient or per-message
  124. option processing, so we return 0 options. And NULL in the OPTIONDATA
  125. structure pointer.
  126. Arguments:
  127. Refer to OLE Documentation on this method.
  128. Return Value:
  129. An HRESULT.
  130. --*/
  131. {
  132. HRESULT hResult = S_OK;
  133. DBG_ENTER(TEXT("CXPLogon::RegisterOptions"),hResult);
  134. *pulFlags = 0;
  135. *pcOptions = 0;
  136. *ppOptions = NULL;
  137. return hResult;
  138. }
  139. STDMETHODIMP
  140. CXPLogon::InitializeStatusRow(
  141. ULONG ulFlags
  142. )
  143. /*++
  144. Routine Description:
  145. To initialize or modify the status properties of a CXPLogon
  146. object. This function allocates an array with NUM_STATUS_ROW_PROPS
  147. properties and initializes them.
  148. Arguments:
  149. ulFlags - 0 if the properties are being created the first time.
  150. MODIFY_FLAGS if a change is being made to the properties
  151. Return Value:
  152. An HRESULT.
  153. --*/
  154. {
  155. HRESULT hResult = S_OK;
  156. DBG_ENTER(TEXT("CXPLogon::InitializeStatusRow"),hResult);
  157. #define NUM_STATUS_ROW_PROPS 7
  158. SPropValue spvStatusRow[NUM_STATUS_ROW_PROPS] = { 0 };
  159. ULONG i = 0;
  160. //
  161. // Set the PR_PROVIDER_DISPLAY property: The transport readable name
  162. //
  163. spvStatusRow[i].ulPropTag = PR_PROVIDER_DISPLAY_A;
  164. spvStatusRow[i++].Value.lpszA = TRANSPORT_DISPLAY_NAME_STRING;
  165. //
  166. // Set the PR_RESOURCE_METHODS property. These are the methods implemented
  167. // in the our IMAPIStatus implementation (CMAPIStatus class.)
  168. //
  169. spvStatusRow[i].ulPropTag = PR_RESOURCE_METHODS;
  170. //
  171. // we support ALL the methods in our implementation of IMAPIStatus interface (except the WRITABLE ones)
  172. //
  173. spvStatusRow[i++].Value.l = STATUS_SETTINGS_DIALOG |
  174. STATUS_FLUSH_QUEUES |
  175. STATUS_VALIDATE_STATE;
  176. //
  177. // Set the PR_STATUS_CODE property.
  178. //
  179. spvStatusRow[i].ulPropTag = PR_STATUS_CODE;
  180. spvStatusRow[i++].Value.l = GetTransportStatusCode();
  181. //
  182. // Set the PR_STATUS_STRING property
  183. //
  184. TCHAR szStatus[64];
  185. char* pcStatus = NULL;
  186. LoadStatusString (szStatus, ARR_SIZE(szStatus));
  187. spvStatusRow[i].ulPropTag = PR_STATUS_STRING_A;
  188. spvStatusRow[i++].Value.lpszA = pcStatus = ConvertTStringToAString(szStatus);
  189. if(!pcStatus)
  190. {
  191. return E_OUTOFMEMORY;
  192. }
  193. //
  194. // Set the PR_DISPLAY_NAME property
  195. //
  196. spvStatusRow[i].ulPropTag = PR_DISPLAY_NAME_A;
  197. spvStatusRow[i++].Value.lpszA = TRANSPORT_DISPLAY_NAME_STRING;
  198. //
  199. // Set the PR_REMOTE_PROGRESS property
  200. //
  201. spvStatusRow[i].ulPropTag = PR_REMOTE_PROGRESS;
  202. spvStatusRow[i++].Value.l = -1; // Not initialized
  203. //
  204. // Set the PR_REMOTE_VALIDATE_OK property
  205. //
  206. spvStatusRow[i].ulPropTag = PR_REMOTE_VALIDATE_OK;
  207. spvStatusRow[i++].Value.b = TRUE;
  208. //
  209. // Write the entries on the provider's session status row
  210. //
  211. hResult = m_pSupObj->ModifyStatusRow (i, spvStatusRow, ulFlags);
  212. MemFree(pcStatus);
  213. return hResult;
  214. }
  215. VOID WINAPI
  216. CXPLogon::UpdateStatus(
  217. BOOL fAddValidate,
  218. BOOL fValidateOkState
  219. )
  220. /*++
  221. Routine Description:
  222. Updates the transport status row of this transport in the MAPI Mail
  223. subsystem. Updates the flags according the internal state flags
  224. maintained in status code of the transport and loads a readable status
  225. string to reset the status row. The caller of this method should update
  226. the status code member variable prior to calling UpdateStatus()
  227. Arguments:
  228. fAddValidate
  229. fValidateOkState
  230. Return Value:
  231. None.
  232. --*/
  233. {
  234. HRESULT hResult = S_OK;
  235. DBG_ENTER(TEXT("CXPLogon::UpdateStatus"),hResult);
  236. ULONG cProps = 1;
  237. SPropValue rgProps[1] = { 0 };
  238. rgProps[0].ulPropTag = PR_STATUS_CODE;
  239. rgProps[0].Value.l = GetTransportStatusCode();
  240. hResult = m_pSupObj->ModifyStatusRow( cProps, rgProps, STATUSROW_UPDATE );
  241. }
  242. BOOL WINAPI
  243. CXPLogon::LoadStatusString(
  244. OUT LPTSTR pString,
  245. IN UINT uStringSize
  246. )
  247. /*++
  248. Routine Description:
  249. Loads a string from the transport's stringtable. This method is called
  250. by the CXPLogon::UpdateStatus method when updating a status row. This
  251. method loads the string based on the status bits of the transport
  252. status code
  253. Arguments:
  254. pString - Pointer to a string which will hold the status string
  255. uStringSize - Maximum number of characters allowed in the string
  256. Return Value:
  257. TRUE - If the string was found in the string table.
  258. FALSE - The string was not found. The String indicated by
  259. pString is set to hold 0 characters
  260. --*/
  261. {
  262. BOOL bRet = TRUE;
  263. DBG_ENTER(TEXT("CXPLogon::LoadStatusString"),bRet);
  264. //
  265. //Make sure we have a terminting NULL
  266. //
  267. pString[uStringSize-1] = '\0';
  268. //
  269. //Copy the string acroding to the size of uStringSize
  270. //
  271. _tcsncpy( pString, _T("Status String"), uStringSize-1);
  272. return bRet;
  273. }
  274. STDMETHODIMP
  275. CXPLogon::TransportNotify(
  276. ULONG * pulFlags,
  277. LPVOID * ppvData
  278. )
  279. /*++
  280. Routine Description:
  281. Update the status row registered by this transport with MAPI.
  282. Arguments:
  283. Refer to MAPI Documentation on this method.
  284. Return Value:
  285. An HRESULT.
  286. --*/
  287. {
  288. HRESULT hResult = S_OK;
  289. DBG_ENTER(TEXT("CXPLogon::TransportNotify"),hResult,TEXT("ulFlags=%d"),*pulFlags);
  290. ULONG ulOldStatus = GetTransportStatusCode();
  291. if (*pulFlags & NOTIFY_BEGIN_INBOUND)
  292. {
  293. RemoveStatusBits( STATUS_INBOUND_ENABLED );
  294. }
  295. if (*pulFlags & NOTIFY_END_INBOUND)
  296. {
  297. RemoveStatusBits( STATUS_INBOUND_ENABLED );
  298. }
  299. if (*pulFlags & NOTIFY_BEGIN_OUTBOUND)
  300. {
  301. AddStatusBits( STATUS_OUTBOUND_ENABLED );
  302. }
  303. if (*pulFlags & NOTIFY_END_OUTBOUND)
  304. {
  305. RemoveStatusBits( STATUS_OUTBOUND_ENABLED );
  306. }
  307. if (*pulFlags & NOTIFY_BEGIN_OUTBOUND_FLUSH)
  308. {
  309. m_pSupObj->SpoolerNotify( NOTIFY_SENTDEFERRED, NULL );
  310. }
  311. if (*pulFlags & NOTIFY_END_OUTBOUND_FLUSH)
  312. {
  313. RemoveStatusBits( STATUS_OUTBOUND_FLUSH );
  314. }
  315. if (*pulFlags & NOTIFY_END_INBOUND_FLUSH)
  316. {
  317. RemoveStatusBits( STATUS_INBOUND_FLUSH );
  318. }
  319. if (ulOldStatus != GetTransportStatusCode())
  320. {
  321. UpdateStatus();
  322. }
  323. return hResult;
  324. }
  325. STDMETHODIMP
  326. CXPLogon::Idle(
  327. ULONG ulFlags
  328. )
  329. /*++
  330. Routine Description:
  331. Stub method. We should not get called here, because we told
  332. the spooler not to call us here.
  333. Arguments:
  334. Refer to MAPI Documentation on this method.
  335. Return Value:
  336. S_OK always.
  337. --*/
  338. {
  339. //
  340. // We should not get called here, because we told
  341. // the spooler not to call us here.
  342. //
  343. DBG_ENTER(TEXT("CXPLogon::Idle"));
  344. Assert(false);
  345. return S_OK;
  346. }
  347. STDMETHODIMP
  348. CXPLogon::TransportLogoff(
  349. ULONG ulFlags
  350. )
  351. /*++
  352. Routine Description:
  353. This method is called by the spooler when the transport should do final
  354. arragements before it gets released.
  355. Arguments:
  356. Refer to MAPI Documentation on this method.
  357. Return Value:
  358. An HRESULT.
  359. --*/
  360. {
  361. HRESULT hResult = S_OK;
  362. DBG_ENTER(TEXT("CXPLogon::TransportLogoff"),hResult,TEXT("ulFlags=%d"),ulFlags);
  363. //
  364. // We should attempt to remove the transport's status row from
  365. // the system
  366. //
  367. hResult = m_pSupObj->ModifyStatusRow (0, NULL, 0);
  368. if (S_OK != hResult)
  369. {
  370. CALL_FAIL (GENERAL_ERR, TEXT("ModifyStatusRow"), hResult);
  371. //
  372. // Don't fail the call
  373. //
  374. hResult = S_OK;
  375. }
  376. return hResult;
  377. }
  378. STDMETHODIMP
  379. CXPLogon::SubmitMessage(
  380. ULONG ulFlags,
  381. LPMESSAGE pMsgObj,
  382. ULONG * pulMsgRef,
  383. ULONG * pulReturnParm
  384. )
  385. /*++
  386. Routine Description:
  387. This method is called by the spooler when a client submits a
  388. message to a recipient whose address type this transport handles.
  389. The spooler calls this method twice for each deferred message.
  390. The first time (before the delivery time) when the message is
  391. submitted by the client, we simply return. The message is then queued
  392. by the spooler for later delivery. We keep track of when it's time
  393. to send deferred messages.
  394. The second time we're called, the state variable will be 'READY' and
  395. we go ahead and start the actual transmission. While we're in the
  396. body of this function, the implied state is 'SENDING'
  397. If the client logs out of this session, any pending messages get
  398. queued again the next time it logs in.
  399. In this transport we get a recipient table, we restrict the table for
  400. unmarked recipients. After the table is ready we invoke a helper
  401. method to do the actual transmission.
  402. Arguments:
  403. Refer to MAPI Documentation on this method.
  404. Return Value:
  405. An HRESULT.
  406. --*/
  407. {
  408. HRESULT hResult = S_OK;
  409. LPADRLIST pOurAdrList = NULL;
  410. ULONG ulRow, ulRecipCount = 0;
  411. LPSPropValue pProps;
  412. FILETIME ft;
  413. SYSTEMTIME st;
  414. BOOL bSentSuccessfully;
  415. ULONG cValues;
  416. LPSPropValue pMsgProps = NULL;
  417. BOOL NeedDeliveryReport;
  418. TCHAR szHeaderText[1024] = {0};
  419. LPSTREAM lpstmT = NULL;
  420. DWORD dwRslt;
  421. TCHAR ErrorText[1024] = {0};
  422. TCHAR FailedText[1024] = {0};
  423. BOOL UseRichText = FALSE;
  424. LPMAPITABLE AttachmentTable = NULL;
  425. LPSRowSet pAttachmentRows = NULL;
  426. LPMAPITABLE pTable = NULL;
  427. LPSRowSet pRecipRows = NULL;
  428. SPropValue propResponsibility = {0};
  429. SPropValue propAddrType = {0};
  430. SRestriction RestrictAnd[2] = {0};
  431. SRestriction Restriction = {0};
  432. DWORD dwRowCount = 0;
  433. DWORD dwRecipientsLimit = 0;
  434. DBG_ENTER(TEXT("CXPLogon::SubmitMessage"),hResult,TEXT("ulFlags=%d"),ulFlags);
  435. CheckSpoolerYield( TRUE );
  436. //
  437. // Get the recipient table from the message
  438. //
  439. hResult = pMsgObj->GetRecipientTable( FALSE , &pTable );
  440. if (FAILED(hResult))
  441. {
  442. goto ErrorExit;
  443. }
  444. //
  445. // The spooler marks all the message recipients this transport has to
  446. // handle with PR_RESPONSIBILITY set to FALSE
  447. // and PR_ADDRTYPE_A is FAX
  448. //
  449. propResponsibility.ulPropTag = PR_RESPONSIBILITY;
  450. propResponsibility.Value.b = FALSE;
  451. propAddrType.ulPropTag = PR_ADDRTYPE_A;
  452. propAddrType.Value.lpszA = FAX_ADDRESS_TYPE_A;
  453. RestrictAnd[0].rt = RES_PROPERTY;
  454. RestrictAnd[0].res.resProperty.relop = RELOP_EQ;
  455. RestrictAnd[0].res.resProperty.ulPropTag = PR_RESPONSIBILITY;
  456. RestrictAnd[0].res.resProperty.lpProp = &propResponsibility;
  457. RestrictAnd[1].rt = RES_PROPERTY;
  458. RestrictAnd[1].res.resProperty.relop = RELOP_EQ;
  459. RestrictAnd[1].res.resProperty.ulPropTag = PR_ADDRTYPE_A;
  460. RestrictAnd[1].res.resProperty.lpProp = &propAddrType;
  461. Restriction.rt = RES_AND;
  462. Restriction.res.resAnd.cRes = 2;
  463. Restriction.res.resAnd.lpRes = RestrictAnd;
  464. hResult = pTable->Restrict( &Restriction, 0 );
  465. if (FAILED(hResult))
  466. {
  467. goto ErrorExit;
  468. }
  469. hResult = pTable->GetRowCount(0, &dwRowCount);
  470. if (FAILED(hResult))
  471. {
  472. goto ErrorExit;
  473. }
  474. if(0 == dwRowCount)
  475. {
  476. //
  477. // There are no fax recipients
  478. //
  479. goto ErrorExit;
  480. }
  481. //
  482. // Let the MAPI spooler do other things
  483. //
  484. CheckSpoolerYield();
  485. hResult = HrAddColumns(
  486. pTable,
  487. (LPSPropTagArray) &sptRecipTable,
  488. gpfnAllocateBuffer,
  489. gpfnFreeBuffer
  490. );
  491. if (FAILED(hResult))
  492. {
  493. goto ErrorExit;
  494. }
  495. hResult = HrQueryAllRows(
  496. pTable,
  497. NULL,
  498. NULL,
  499. NULL,
  500. 0,
  501. &pRecipRows
  502. );
  503. if (FAILED(hResult))
  504. {
  505. goto ErrorExit;
  506. }
  507. //
  508. // Let the MAPI spooler do other things
  509. //
  510. CheckSpoolerYield();
  511. //
  512. //Get the message properties
  513. //
  514. hResult = pMsgObj->GetProps(
  515. (LPSPropTagArray) &sptPropsForHeader,
  516. 0,
  517. &cValues,
  518. &pMsgProps
  519. );
  520. if (!HR_SUCCEEDED(hResult))
  521. {
  522. CALL_FAIL(GENERAL_ERR, TEXT("GetProps"), hResult);
  523. goto ErrorExit;
  524. }
  525. hResult = pMsgObj->OpenProperty(
  526. PR_RTF_COMPRESSED,
  527. &IID_IStream,
  528. 0,
  529. 0,
  530. (LPUNKNOWN*) &lpstmT
  531. );
  532. if (FAILED(hResult))
  533. {
  534. hResult = pMsgObj->OpenProperty(
  535. PR_BODY,
  536. &IID_IStream,
  537. 0,
  538. 0,
  539. (LPUNKNOWN*) &lpstmT
  540. );
  541. if (FAILED(hResult))
  542. {
  543. //
  544. // the message body is empty
  545. //
  546. lpstmT = NULL;
  547. }
  548. hResult = S_OK;
  549. }
  550. else
  551. {
  552. UseRichText = TRUE;
  553. }
  554. if (PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED == pMsgProps[MSG_DR_REPORT].ulPropTag && pMsgProps[MSG_DR_REPORT].Value.b)
  555. {
  556. NeedDeliveryReport = TRUE;
  557. }
  558. else
  559. {
  560. NeedDeliveryReport = FALSE;
  561. }
  562. GetSystemTime (&st);
  563. if(!SystemTimeToFileTime(&st, &ft))
  564. {
  565. dwRslt = ::GetLastError ();
  566. CALL_FAIL (RESOURCE_ERR, TEXT("SystemTimeToFileTime"), dwRslt);
  567. }
  568. //
  569. // submit the fax
  570. //
  571. dwRslt = SendFaxDocument
  572. (
  573. pMsgObj,
  574. lpstmT,
  575. UseRichText,
  576. pMsgProps,
  577. pRecipRows,
  578. &dwRecipientsLimit
  579. );
  580. bSentSuccessfully = (dwRslt == S_OK);
  581. for (ulRow=0; ulRow<pRecipRows->cRows; ulRow++)
  582. {
  583. pProps = pRecipRows->aRow[ulRow].lpProps;
  584. //
  585. // Update the PR_RESPONSIBILITY to TRUE, so that MAPI will ask another transport
  586. // provider to try and send it.
  587. //
  588. pProps[RECIP_RESPONSIBILITY].ulPropTag = PR_RESPONSIBILITY;
  589. pProps[RECIP_RESPONSIBILITY].Value.b = TRUE;
  590. if (!bSentSuccessfully)
  591. {
  592. //
  593. // for each recipient: insert NDR string as a property value, update delivery time as NULL,
  594. // and live the PR_RESPONSIBILITY == false, so that MAPI will try to send the fax via another
  595. // transport provider.
  596. //
  597. pProps[RECIP_DELIVER_TIME].ulPropTag = PR_NULL;
  598. LoadString( g_hResource, IDS_FAILED_MESSAGE, FailedText, sizeof(FailedText) / sizeof(FailedText[0]));
  599. if (IDS_RECIPIENTS_LIMIT == dwRslt)
  600. {
  601. //
  602. // Recipient limit NDR
  603. //
  604. TCHAR TmpErrorText[1024] = {0};
  605. LoadString( g_hResource, dwRslt, TmpErrorText, ARR_SIZE(TmpErrorText));
  606. _sntprintf( ErrorText, ARR_SIZE(ErrorText)-1, TmpErrorText, pRecipRows->cRows, dwRecipientsLimit);
  607. }
  608. else
  609. {
  610. LoadString( g_hResource, dwRslt, ErrorText, sizeof(ErrorText) / sizeof(ErrorText[0]));
  611. }
  612. _sntprintf( szHeaderText, ARR_SIZE(szHeaderText)-1, _T("\t%s\r\n\t%s\r\n"),FailedText, ErrorText);
  613. LPSTR pTmpStr = ConvertTStringToAString(szHeaderText);
  614. if (!pTmpStr)
  615. {
  616. hResult = ERROR_NOT_ENOUGH_MEMORY;
  617. goto ErrorExit;
  618. }
  619. LPSTR pStrA;
  620. hResult = gpfnAllocateMore( CbtszsizeA(pTmpStr), pProps, (LPVOID *)&pStrA );
  621. if (SUCCEEDED(hResult))
  622. {
  623. //
  624. // Copy the formatted string and hook it into the pre-allocated (by MAPI) column
  625. //
  626. _mbscpy ((PUCHAR)pStrA, (PUCHAR)pTmpStr);//pStrA is preAllocated. no need to check for NULL
  627. pProps[RECIP_REPORT_TEXT].ulPropTag = PR_REPORT_TEXT_A;
  628. pProps[RECIP_REPORT_TEXT].Value.lpszA = pStrA;
  629. }
  630. else
  631. {
  632. pProps[RECIP_REPORT_TEXT].ulPropTag = PROP_TAG (PT_ERROR, PROP_ID (PR_REPORT_TEXT));
  633. pProps[RECIP_REPORT_TEXT].Value.err = hResult;
  634. }
  635. MemFree(pTmpStr);
  636. pTmpStr = NULL;
  637. gpfnFreeBuffer(pStrA); //allocated with gpfnAllocateMore which is MAPIAllocateMore
  638. pStrA = NULL;
  639. }
  640. else
  641. {
  642. //
  643. // for each recipient: insert DR string as a property value, update delivery time,
  644. // For delivery report, each recipient must have this property set.
  645. // Otherwise the spooler will default to generate an NDR instead.
  646. //
  647. pProps[RECIP_DELIVER_TIME].ulPropTag = PR_DELIVER_TIME;
  648. pProps[RECIP_DELIVER_TIME].Value.ft = ft;
  649. pProps[RECIP_REPORT_TEXT].ulPropTag = PROP_TAG (PT_ERROR, PROP_ID (PR_REPORT_TEXT));
  650. pProps[RECIP_REPORT_TEXT].Value.err = S_OK;
  651. }
  652. //
  653. // add this recipient to a recipients list, that includes only the recipients we've tried
  654. // to send to. (we either succeeded to queue all of them or we failed to queue all of them).
  655. //
  656. //
  657. // Does the list where this recipient goes have enough room for one more entry?
  658. // If not, resize the address list to hold QUERY_SIZE more entries.
  659. //
  660. if (!(pOurAdrList ) || ((pOurAdrList)->cEntries + 1 > ulRecipCount))
  661. {
  662. hResult= GrowAddressList( &pOurAdrList , 10, &ulRecipCount );
  663. if (FAILED(hResult))
  664. {
  665. goto ErrorExit;
  666. }
  667. }
  668. //
  669. // We have room now so store the new ADRENTRY. As part of the
  670. // storage, we're going to copy the SRow pointer from the SRowSet
  671. // into the ADRENTRY. Once we've done this, we won't need the
  672. // SRowSet any more ... and the SRow will be released when
  673. // we unwind OurAdrList
  674. //
  675. (pOurAdrList)->aEntries[(pOurAdrList)->cEntries].cValues = pRecipRows->aRow[ulRow].cValues;
  676. (pOurAdrList)->aEntries[(pOurAdrList)->cEntries].rgPropVals = pRecipRows->aRow[ulRow].lpProps;
  677. //
  678. // Increase the number of entries in the address list
  679. //
  680. (pOurAdrList)->cEntries++;
  681. }
  682. //
  683. // Now we need to save changes on the message and close it.
  684. // After this, the message object can't be used.
  685. //
  686. hResult = pMsgObj->SaveChanges(0);
  687. switch (hResult)
  688. {
  689. case S_OK:
  690. case MAPI_E_NO_ACCESS:
  691. break;
  692. case MAPI_E_OBJECT_DELETED:
  693. case MAPI_E_OBJECT_CHANGED:
  694. goto ErrorExit;
  695. default: break;
  696. }
  697. //
  698. // Let the MAPI spooler do other things
  699. //
  700. CheckSpoolerYield();
  701. //
  702. // change our MsgObj's recipients list, so that it'll include only those that got the message.
  703. //
  704. if(pOurAdrList)
  705. {
  706. hResult = pMsgObj->ModifyRecipients( MODRECIP_MODIFY, pOurAdrList);
  707. hResult = S_OK;
  708. //
  709. // We'll drop the error code from the modify recipients call
  710. //
  711. }
  712. if (bSentSuccessfully)
  713. {
  714. if ((NeedDeliveryReport) && (pOurAdrList))
  715. {
  716. VERBOSE (DBG_MSG, TEXT("xport\\xplogon.cpp\\SubmitMessage: Sending delivery Report"));
  717. //
  718. //let spooler know he has to send delivery rec. to those addresses.
  719. //
  720. hResult = m_pSupObj->StatusRecips( pMsgObj, pOurAdrList);
  721. if (!HR_FAILED(hResult))
  722. {
  723. //
  724. // If we were successful, we should null out the pointer becase MAPI released
  725. // the memory for this structure. And we should not try to release it
  726. // again in the cleanup code.
  727. //
  728. pOurAdrList = NULL;
  729. }
  730. }
  731. }
  732. if (! bSentSuccessfully)
  733. {
  734. if(pOurAdrList)
  735. {
  736. hResult = pMsgObj->ModifyRecipients( MODRECIP_MODIFY, pOurAdrList);
  737. //
  738. // We'll drop the error code from the modify recipients call
  739. //
  740. VERBOSE (DBG_MSG, TEXT("xport\\xplogon.cpp\\SubmitMessage: Sending UnDelivery Report"));
  741. //
  742. //let spooler know he has to send undelivery rec. to those addresses.
  743. //
  744. hResult = m_pSupObj->StatusRecips( pMsgObj, pOurAdrList);
  745. if (!HR_FAILED(hResult))
  746. {
  747. //
  748. // If we were successful, we should null out the pointer becase MAPI released
  749. // the memory for this structure. And we should not try to release it
  750. // again in the cleanup code.
  751. //
  752. pOurAdrList = NULL;
  753. }
  754. }
  755. }
  756. ErrorExit:
  757. //
  758. // Release the table, we're finished with it
  759. //
  760. if (pTable)
  761. {
  762. pTable->Release();
  763. }
  764. if (pRecipRows)
  765. {
  766. FreeProws( pRecipRows );
  767. }
  768. if (pMsgProps)
  769. {
  770. MAPIFreeBuffer( pMsgProps );
  771. pMsgProps = NULL;
  772. }
  773. if (lpstmT)
  774. {
  775. lpstmT->Release();
  776. }
  777. if(pOurAdrList)
  778. {
  779. MAPIFreeBuffer(pOurAdrList);
  780. }
  781. //
  782. // In case there is a warning or error floating around, don't let it escape to the spooler.
  783. //
  784. if (FAILED(hResult))
  785. {
  786. //
  787. // We default to MAPI_E_NOT_ME so that the spooler would attempt handle
  788. // the message to other transport (currently running in this profile)
  789. // that handle the same address type as ours.
  790. //
  791. hResult = MAPI_E_NOT_ME;
  792. }
  793. else
  794. {
  795. hResult = S_OK;
  796. }
  797. return hResult;
  798. }
  799. STDMETHODIMP
  800. CXPLogon::GrowAddressList(
  801. LPADRLIST *ppAdrList,
  802. ULONG ulResizeBy,
  803. ULONG *pulOldAndNewCount
  804. )
  805. /*++
  806. Routine Description:
  807. In this function, given an address list with pulOldAndNewCount of
  808. entries, we resize the address list to hold the old number of
  809. entries plus the ulResizeBy entries. The old address list contents
  810. are copied to the new list and the count reset. The memory for the
  811. old address list is released here.
  812. Arguments:
  813. ppAdrList - Pointer to an address where the old address list
  814. is and where the new resized address list will
  815. be returned
  816. ulResizeBy - Number of new address entries to add to the list
  817. pulOldAndNewCount - Number of entries in the old address list. In
  818. this parameter, upon sucessful return, will have
  819. the number of in the new address list
  820. Return Value:
  821. An HRESULT.
  822. --*/
  823. {
  824. HRESULT hResult = S_OK;
  825. DBG_ENTER(TEXT("CXPLogon::GrowAddressList"),hResult);
  826. LPADRLIST pNewAdrList;
  827. // Calculate how big the new buffer for the expanded address list should be
  828. ULONG cbSize = CbNewADRLIST ((*pulOldAndNewCount) + ulResizeBy);
  829. // Allocate the memory for it
  830. hResult = gpfnAllocateBuffer (cbSize, (LPVOID *)&pNewAdrList);
  831. if (FAILED(hResult))
  832. {
  833. // We can't continue
  834. return hResult;
  835. }
  836. // Zero-out all memory for neatness
  837. ZeroMemory (pNewAdrList, cbSize);
  838. // If we had entries in the old address list, copy the memory from
  839. // the old addres list into the new expanded list
  840. if ((*pulOldAndNewCount))
  841. {
  842. CopyMemory( pNewAdrList, *ppAdrList, CbNewADRLIST ((*pulOldAndNewCount)) );
  843. }
  844. // Set the number of entries in the new address list to the OLD size
  845. pNewAdrList->cEntries = (*pulOldAndNewCount);
  846. // We must return the number of available entries in the new expanded address list
  847. (*pulOldAndNewCount) += ulResizeBy;
  848. // Free the old memory and put the new pointer in place
  849. gpfnFreeBuffer (*ppAdrList);
  850. *ppAdrList = pNewAdrList;
  851. return hResult;
  852. }
  853. STDMETHODIMP
  854. CXPLogon::EndMessage(
  855. ULONG ulMsgRef,
  856. ULONG *pulFlags
  857. )
  858. /*++
  859. Routine Description:
  860. This method is called by the spooler for each message we're to
  861. deliver. It's the mate to SubmitMessage. We're called here twice
  862. for each deferred message and once for non-deferred (realtime)
  863. messages.
  864. We first check the transport state, and if we're
  865. WAITING for the scheduled delivery time to arrive, we return
  866. END_DONT_RESEND in *pulFlags, which tells the spooler to queue this
  867. message for deferred delivery.
  868. If the state is SENDING, we're getting called here after
  869. a message has been dequeued and delivered. Return 0 in *pulFlags
  870. to tell the spooler the message has been delivered.
  871. Arguments:
  872. Refer to MAPI Documentation on this method.
  873. Return Value:
  874. An HRESULT.
  875. --*/
  876. {
  877. HRESULT hResult = S_OK;
  878. DBG_ENTER(TEXT("CXPLogon::EndMessage"),hResult);
  879. *pulFlags = 0;
  880. return hResult;
  881. }
  882. STDMETHODIMP
  883. CXPLogon::Poll(
  884. ULONG *pulIncoming
  885. )
  886. /*++
  887. Routine Description:
  888. Stub method. We should not get called here, because we told
  889. the spooler not to call us here.
  890. Arguments:
  891. Refer to MAPI Documentation on this method.
  892. Return Value:
  893. An HRESULT.
  894. --*/
  895. {
  896. return S_OK;
  897. }
  898. STDMETHODIMP
  899. CXPLogon::StartMessage(
  900. ULONG ulFlags,
  901. LPMESSAGE pMsgObj,
  902. ULONG * pulMsgRef
  903. )
  904. /*++
  905. Routine Description:
  906. This method gets called when an incoming message is pending to be
  907. processed.
  908. Arguments:
  909. Refer to MAPI Documentation on this method.
  910. Return Value:
  911. An HRESULT.
  912. --*/
  913. {
  914. DBG_ENTER(TEXT("CXPLogon::StartMessage"));
  915. //
  916. //We should not get called here since we don't deal with incoming messages
  917. //
  918. Assert(false);
  919. return S_OK;
  920. }
  921. STDMETHODIMP
  922. CXPLogon::OpenStatusEntry(
  923. LPCIID pInterface,
  924. ULONG ulFlags,
  925. ULONG * pulObjType,
  926. LPMAPISTATUS * ppEntry
  927. )
  928. /*++
  929. Routine Description:
  930. This method is called to get an IMAPIStatus object for this XPLOGON
  931. session.
  932. Arguments:
  933. Refer to MAPI Documentation on this method.
  934. Return Value:
  935. An HRESULT.
  936. --*/
  937. {
  938. HRESULT hResult = S_OK;
  939. DBG_ENTER(TEXT("CXPLogon::OpenStatusEntry"),hResult);
  940. if (MAPI_MODIFY & ulFlags)
  941. {
  942. hResult = E_ACCESSDENIED;
  943. goto exit;
  944. }
  945. *pulObjType = MAPI_STATUS;
  946. exit:
  947. return hResult;
  948. }
  949. STDMETHODIMP
  950. CXPLogon::ValidateState(
  951. ULONG ulUIParam,
  952. ULONG ulFlags
  953. )
  954. /*++
  955. Routine Description:
  956. This function gets caller by a client in order to validate the
  957. transport logon properties. This function open the profile with the
  958. most up-to-date properties and then compares them to what the transport
  959. has stored internally.
  960. Arguments:
  961. Refer to MAPI Documentation on this method.
  962. Return Value:
  963. An HRESULT.
  964. --*/
  965. {
  966. return S_OK;
  967. }
  968. STDMETHODIMP
  969. CXPLogon::FlushQueues(
  970. ULONG ulUIParam,
  971. ULONG cbTargetTransport,
  972. LPENTRYID pTargetTransport,
  973. ULONG ulFlags
  974. )
  975. /*++
  976. Routine Description:
  977. Called by the MAPI spooler when, upon request of the client or
  978. ourselves, we need to flush the inbound or outbound queue.
  979. Here we make connections to the server to download messages, refresh
  980. the remote message headers, and request the spooler to send us any
  981. deferred messages.
  982. Transport connecting only in FlushQueues() allow the MAPI spooler to
  983. better manage contention of multiple transport accessing common
  984. communication resources (such as COM ports) and let the spooler give us
  985. messages to process when is best for the overall subsystem.
  986. Arguments:
  987. Refer to MAPI Documentation on this method.
  988. Return Value:
  989. An HRESULT.
  990. --*/
  991. {
  992. return S_OK;
  993. }
  994. void WINAPI
  995. CXPLogon::CheckSpoolerYield(
  996. BOOL fReset
  997. )
  998. /*++
  999. Routine Description:
  1000. Enforce the 0.2 second rule for transport that need to yield to the
  1001. MAPI spooler. Called periodically while processing a message to
  1002. determine if we have used more than 0.2 seconds. If so, then call
  1003. SpoolerYield(), else just continue.
  1004. This is called with fReset set to TRUE when we first enter one
  1005. of the Transport Logon methods (usually one that is known to
  1006. take a long time like StartMessage() or SubmitMessage(). )
  1007. Arguments:
  1008. Refer to MAPI Documentation on this method.
  1009. Return Value:
  1010. An HRESULT.
  1011. --*/
  1012. {
  1013. DWORD dwStop;
  1014. static DWORD dwStart;
  1015. if (fReset)
  1016. {
  1017. dwStart = GetTickCount();
  1018. }
  1019. else
  1020. {
  1021. dwStop = GetTickCount();
  1022. if ((dwStop - dwStart) > 200) // 200 milliseconds
  1023. {
  1024. m_pSupObj->SpoolerYield (0);
  1025. dwStart = GetTickCount();
  1026. }
  1027. }
  1028. }
  1029. STDMETHODIMP_(ULONG)
  1030. CXPLogon::AddRef()
  1031. /*++
  1032. Routine Description:
  1033. Arguments:
  1034. Refer to MAPI Documentation on this method.
  1035. Return Value:
  1036. An HRESULT.
  1037. --*/
  1038. {
  1039. ++m_cRef;
  1040. return m_cRef;
  1041. }
  1042. STDMETHODIMP_(ULONG)
  1043. CXPLogon::Release()
  1044. /*++
  1045. Routine Description:
  1046. Arguments:
  1047. Refer to MAPI Documentation on this method.
  1048. Return Value:
  1049. An HRESULT.
  1050. --*/
  1051. {
  1052. ULONG ulCount = --m_cRef;
  1053. if (!ulCount)
  1054. {
  1055. delete this;
  1056. }
  1057. return ulCount;
  1058. }