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.

1358 lines
36 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. config.cpp
  5. Abstract:
  6. This module contains routines for the fax config dialog.
  7. Author:
  8. Wesley Witt (wesw) 13-Aug-1996
  9. Revision History:
  10. 20/10/99 -danl-
  11. Handle errors, and get appropriate server name in GetFaxConfig.
  12. dd/mm/yy -author-
  13. description
  14. --*/
  15. #define INITGUID
  16. #define USES_IID_IExchExt
  17. #define USES_IID_IExchExtAdvancedCriteria
  18. #define USES_IID_IExchExtAttachedFileEvents
  19. #define USES_IID_IExchExtCommands
  20. #define USES_IID_IExchExtMessageEvents
  21. #define USES_IID_IExchExtPropertySheets
  22. #define USES_IID_IExchExtSessionEvents
  23. #define USES_IID_IExchExtUserEvents
  24. #define USES_IID_IMAPIFolder
  25. #define USES_IID_IProfAdmin
  26. #define USES_IID_IProfSect
  27. #define USES_IID_IMAPISession
  28. #define USES_PS_PUBLIC_STRINGS
  29. #define USES_IID_IDistList
  30. #include "faxext.h"
  31. #include <initguid.h>
  32. #include "debugex.h"
  33. #include <mbstring.h>
  34. #include <faxres.h>
  35. HINSTANCE g_hModule = NULL; // DLL handle
  36. HINSTANCE g_hResource = NULL; // Resource DLL handle
  37. BOOL WINAPI
  38. DllMain(
  39. HINSTANCE hinstDLL,
  40. DWORD fdwReason,
  41. LPVOID lpvReserved
  42. )
  43. {
  44. if (fdwReason == DLL_PROCESS_ATTACH)
  45. {
  46. DisableThreadLibraryCalls(hinstDLL);
  47. g_hModule = hinstDLL;
  48. g_hResource = GetResInstance(hinstDLL);
  49. if(!g_hResource)
  50. {
  51. return FALSE;
  52. }
  53. HeapInitialize( NULL, MapiMemAlloc, MapiMemFree, MapiMemReAlloc);
  54. }
  55. else if (fdwReason == DLL_PROCESS_DETACH)
  56. {
  57. FreeResInstance();
  58. }
  59. return TRUE;
  60. }
  61. BOOL
  62. VerifyDistributionList(
  63. LPEXCHEXTCALLBACK pmecb,
  64. DWORD EntryIdSize,
  65. LPENTRYID EntryId
  66. )
  67. {
  68. HRESULT hr = S_OK;
  69. LPMAPISESSION Session = NULL;
  70. LPDISTLIST DistList = NULL;
  71. DWORD ObjType = 0;
  72. LPMAPITABLE DistTable = NULL;
  73. LPSRowSet DistRows = NULL;
  74. LPSPropValue Dist = NULL;
  75. DWORD i,j;
  76. BOOL FaxAddress = FALSE;
  77. hr = pmecb->GetSession( &Session, NULL );
  78. if (FAILED(hr)) {
  79. goto exit;
  80. }
  81. hr = Session->OpenEntry(
  82. EntryIdSize,
  83. EntryId,
  84. &IID_IDistList,
  85. MAPI_DEFERRED_ERRORS,
  86. &ObjType,
  87. (LPUNKNOWN *) &DistList
  88. );
  89. if (FAILED(hr))
  90. {
  91. goto exit;
  92. }
  93. hr = DistList->GetContentsTable(
  94. MAPI_DEFERRED_ERRORS,
  95. &DistTable
  96. );
  97. if (FAILED(hr))
  98. {
  99. goto exit;
  100. }
  101. hr = HrQueryAllRows( DistTable, NULL, NULL, NULL, 0, &DistRows );
  102. if (FAILED(hr))
  103. {
  104. goto exit;
  105. }
  106. for (i=0; i<DistRows->cRows; i++)
  107. {
  108. Dist = DistRows->aRow[i].lpProps;
  109. for (j=0; j<DistRows->aRow[i].cValues; j++)
  110. {
  111. if (Dist[j].ulPropTag == PR_ADDRTYPE_A)
  112. {
  113. if (!strcmp( Dist[j].Value.lpszA, "FAX" ))
  114. {
  115. FaxAddress = TRUE;
  116. }
  117. }
  118. else if (Dist[j].ulPropTag == PR_ADDRTYPE_W)
  119. {
  120. if (!wcscmp( Dist[j].Value.lpszW, L"FAX" ))
  121. {
  122. FaxAddress = TRUE;
  123. }
  124. }
  125. }
  126. }
  127. exit:
  128. if (Session) {
  129. Session->Release();
  130. }
  131. if (DistList) {
  132. DistList->Release();
  133. }
  134. if (DistTable) {
  135. MemFree( DistTable );
  136. }
  137. if (DistRows) {
  138. FreeProws( DistRows );
  139. }
  140. return FaxAddress;
  141. }
  142. BOOL
  143. VerifyFaxRecipients(
  144. LPEXCHEXTCALLBACK pmecb
  145. )
  146. /*++
  147. Routine name : VerifyFaxRecipients
  148. Routine description:
  149. Gets the recipients list of the currently open item, and checks wheather there
  150. are any fax recipients in it. for a DL recipient - calls VerifyDistributionList
  151. to check if there are any fax recipients in the DL.
  152. Author:
  153. Keren Ellran (t-KerenE), Mar, 2000
  154. Arguments:
  155. pmecb -- [IN] pointer to Exchange Extension callback function
  156. Return Value:
  157. BOOL: TRUE if there's one or more fax recipients, FALSE if none
  158. --*/
  159. {
  160. HRESULT hr = S_OK;
  161. LPADRLIST AdrList = NULL;
  162. DWORD i,j;
  163. BOOL FaxAddress = FALSE;
  164. BOOL IsDistList = FALSE;
  165. LPENTRYID EntryId = NULL;
  166. DWORD EntryIdSize;
  167. hr = pmecb->GetRecipients( &AdrList );
  168. if (FAILED(hr))
  169. {
  170. goto exit;
  171. }
  172. if (AdrList)
  173. {
  174. for (i=0; i<AdrList->cEntries; i++)
  175. {
  176. EntryId = NULL;
  177. IsDistList = FALSE;
  178. for (j=0; j<AdrList->aEntries[i].cValues; j++)
  179. {
  180. if (AdrList->aEntries[i].rgPropVals[j].ulPropTag == PR_ENTRYID)
  181. {
  182. EntryId = (LPENTRYID) AdrList->aEntries[i].rgPropVals[j].Value.bin.lpb;
  183. EntryIdSize = AdrList->aEntries[i].rgPropVals[j].Value.bin.cb;
  184. }
  185. else if (AdrList->aEntries[i].rgPropVals[j].ulPropTag == PR_ADDRTYPE_A)
  186. {
  187. if (!strcmp(AdrList->aEntries[i].rgPropVals[j].Value.lpszA, "FAX"))
  188. {
  189. FaxAddress = TRUE;
  190. goto exit;
  191. }
  192. else if ((!strcmp(AdrList->aEntries[i].rgPropVals[j].Value.lpszA, "MAPIPDL" )))
  193. {
  194. IsDistList = TRUE;
  195. }
  196. }
  197. else if (AdrList->aEntries[i].rgPropVals[j].ulPropTag == PR_ADDRTYPE_W)
  198. {
  199. //
  200. // Outlook Beta 2 (10.2202.2202) does not supply PR_ADDRTYPE_A property
  201. // so we are looking for a PR_ADDRTYPE_W
  202. //
  203. if (!wcscmp(AdrList->aEntries[i].rgPropVals[j].Value.lpszW, L"FAX" ))
  204. {
  205. FaxAddress = TRUE;
  206. goto exit;
  207. }
  208. else if ((!wcscmp(AdrList->aEntries[i].rgPropVals[j].Value.lpszW, L"MAPIPDL")))
  209. {
  210. IsDistList = TRUE;
  211. }
  212. }
  213. }
  214. //
  215. // after we finished going over all address's properties, if it is a DL,
  216. // and if EntryId was detected, we can check if the DL includes a fax address.
  217. //
  218. if ((IsDistList)&&(EntryId))
  219. {
  220. FaxAddress = VerifyDistributionList( pmecb, EntryIdSize, EntryId );
  221. if (FaxAddress == TRUE)
  222. goto exit;
  223. }
  224. }
  225. }
  226. exit:
  227. if(AdrList)
  228. {
  229. FreePadrlist(AdrList);
  230. }
  231. return FaxAddress;
  232. }
  233. HRESULT
  234. EnableMenuAndToolbar(
  235. LPEXCHEXTCALLBACK pmecb,
  236. HWND hwndToolbar,
  237. DWORD CmdId
  238. )
  239. {
  240. HRESULT hr = S_OK;
  241. LPADRLIST AdrList = NULL;
  242. BOOL FaxAddress = FALSE;
  243. HMENU hMenu;
  244. LPENTRYID EntryId = NULL;
  245. DBG_ENTER(TEXT("EnableMenuAndToolbar"));
  246. FaxAddress = VerifyFaxRecipients(pmecb);
  247. hr = pmecb->GetMenu( &hMenu );
  248. if (S_OK != hr)
  249. {
  250. goto exit;
  251. }
  252. if (FaxAddress)
  253. {
  254. VERBOSE(DBG_MSG, TEXT("Enabling menu") );
  255. EnableMenuItem( hMenu, CmdId, MF_BYCOMMAND | MF_ENABLED );
  256. SendMessage( hwndToolbar, TB_ENABLEBUTTON, (WPARAM) CmdId, MAKELONG(TRUE,0) );
  257. }
  258. else
  259. {
  260. VERBOSE(DBG_MSG, TEXT("Disabling menu") );
  261. EnableMenuItem( hMenu, CmdId, MF_BYCOMMAND | MF_GRAYED );
  262. SendMessage( hwndToolbar, TB_ENABLEBUTTON, (WPARAM) CmdId, MAKELONG(FALSE,0) );
  263. }
  264. exit:
  265. return hr;
  266. }
  267. HRESULT
  268. GetFaxConfig(
  269. LPEXCHEXTCALLBACK pmecb,
  270. PFAXXP_CONFIG FaxConfig
  271. )
  272. {
  273. HRESULT hr = S_FALSE;
  274. LPMAPISESSION lpSession = NULL;
  275. LPPROFSECT pProfileObj = NULL;
  276. ULONG PropCount = 0;
  277. LPSPropValue pProps = NULL;
  278. LPSERVICEADMIN lpServiceAdmin = NULL;
  279. LPPROVIDERADMIN lpProviderAdmin = NULL;
  280. LPMAPITABLE ptblSvc = NULL;
  281. LPSRowSet pSvcRows = NULL;
  282. LPSPropValue pSvc = NULL;
  283. DWORD i,j;
  284. BOOL FoundIt = FALSE;
  285. LPBYTE FaxXpGuid = NULL;
  286. MAPIUID FaxGuid = FAX_XP_GUID;
  287. hr = pmecb->GetSession( &lpSession, NULL );
  288. if (FAILED(hr)) {
  289. goto exit;
  290. }
  291. hr = lpSession->AdminServices( 0, &lpServiceAdmin );
  292. if (FAILED(hr)) {
  293. goto exit;
  294. }
  295. hr = lpServiceAdmin->GetMsgServiceTable( 0, &ptblSvc );
  296. if (FAILED(hr)) {
  297. goto exit;
  298. }
  299. hr = HrQueryAllRows( ptblSvc, NULL, NULL, NULL, 0, &pSvcRows );
  300. if (FAILED(hr)) {
  301. goto exit;
  302. }
  303. for (i=0; i<pSvcRows->cRows; i++)
  304. {
  305. pSvc = pSvcRows->aRow[i].lpProps;
  306. for (j=0; j<pSvcRows->aRow[i].cValues; j++)
  307. {
  308. if (pSvc[j].ulPropTag == PR_SERVICE_NAME_A)
  309. {
  310. // look for the name of the service as registered on XP and .NET
  311. if (_stricmp( pSvc[j].Value.lpszA, FAX_MESSAGE_SERVICE_NAME) == 0)
  312. {
  313. FoundIt = TRUE;
  314. }
  315. // look for the name of the service as registered on down level clients
  316. if (_stricmp( pSvc[j].Value.lpszA, FAX_MESSAGE_SERVICE_NAME_SBS50) == 0)
  317. {
  318. FoundIt = TRUE;
  319. }
  320. }
  321. if (pSvc[j].ulPropTag == PR_SERVICE_UID)
  322. {
  323. FaxXpGuid = pSvc[j].Value.bin.lpb;
  324. }
  325. }
  326. if (FoundIt)
  327. {
  328. break;
  329. }
  330. }
  331. if (!FoundIt)
  332. {
  333. goto exit;
  334. }
  335. hr = lpServiceAdmin->AdminProviders( (LPMAPIUID) FaxXpGuid, 0, &lpProviderAdmin );
  336. if (FAILED(hr))
  337. {
  338. goto exit;
  339. }
  340. hr = lpProviderAdmin->OpenProfileSection(
  341. &FaxGuid,
  342. NULL,
  343. 0,
  344. &pProfileObj);
  345. if (FAILED(hr))
  346. {
  347. goto exit;
  348. }
  349. hr = pProfileObj->GetProps(
  350. (LPSPropTagArray) &sptFaxProps,
  351. 0,
  352. &PropCount,
  353. &pProps);
  354. if (S_OK != hr)
  355. {
  356. goto exit;
  357. }
  358. if(pProps[PROP_FAX_PRINTER_NAME].Value.bin.lpb)
  359. {
  360. FaxConfig->PrinterName = StringDup((LPTSTR)pProps[PROP_FAX_PRINTER_NAME].Value.bin.lpb );
  361. if (!FaxConfig->PrinterName)
  362. {
  363. hr = E_OUTOFMEMORY;
  364. goto exit;
  365. }
  366. }
  367. if(pProps[PROP_COVERPAGE_NAME].Value.bin.lpb)
  368. {
  369. FaxConfig->CoverPageName = StringDup( (LPTSTR)pProps[PROP_COVERPAGE_NAME].Value.bin.lpb );
  370. if (!FaxConfig->CoverPageName)
  371. {
  372. hr = E_OUTOFMEMORY;
  373. goto exit;
  374. }
  375. }
  376. FaxConfig->UseCoverPage = pProps[PROP_USE_COVERPAGE].Value.ul;
  377. FaxConfig->SendSingleReceipt = pProps[PROP_SEND_SINGLE_RECEIPT].Value.ul;
  378. FaxConfig->bAttachFax = pProps[PROP_ATTACH_FAX].Value.ul;
  379. FaxConfig->ServerCoverPage = pProps[PROP_SERVER_COVERPAGE].Value.ul;
  380. if(pProps[PROP_FONT].Value.bin.lpb && sizeof(LOGFONT) == pProps[PROP_FONT].Value.bin.cb)
  381. {
  382. if (!memcpy( &FaxConfig->FontStruct, pProps[PROP_FONT].Value.bin.lpb, pProps[PROP_FONT].Value.bin.cb ))
  383. {
  384. hr = E_OUTOFMEMORY;
  385. goto exit;
  386. }
  387. }
  388. if (!GetServerNameFromPrinterName(FaxConfig->PrinterName,&FaxConfig->ServerName))
  389. {
  390. hr = S_FALSE;
  391. goto exit;
  392. }
  393. hr = S_OK;
  394. exit:
  395. if (pSvcRows) {
  396. FreeProws( pSvcRows );
  397. }
  398. if (pProps) {
  399. MAPIFreeBuffer( pProps );
  400. }
  401. if (pProfileObj) {
  402. pProfileObj->Release();
  403. }
  404. if (ptblSvc) {
  405. ptblSvc->Release();
  406. }
  407. if (lpProviderAdmin) {
  408. lpProviderAdmin->Release();
  409. }
  410. if (lpServiceAdmin) {
  411. lpServiceAdmin->Release();
  412. }
  413. if (lpSession) {
  414. lpSession->Release();
  415. }
  416. return hr;
  417. }
  418. ///////////////////////////////////////////////////////////////////////////////
  419. // FUNCTION: ExchEntryPoint
  420. //
  421. // Parameters - none
  422. //
  423. // Purpose
  424. // The entry point which Exchange calls.
  425. //
  426. // Return Value
  427. // Pointer to Exchange Extension Object
  428. //
  429. // Comments
  430. // This is called for each context entry. Create a new MyExchExt object
  431. // every time so each context will get its own MyExchExt interface.
  432. //
  433. LPEXCHEXT CALLBACK ExchEntryPoint(void)
  434. {
  435. MyExchExt* pExt = new MyExchExt;
  436. if (pExt && !pExt->IsValid())
  437. {
  438. //
  439. // Creation failed
  440. //
  441. delete pExt;
  442. pExt = NULL;
  443. }
  444. return pExt;
  445. }
  446. ///////////////////////////////////////////////////////////////////////////////
  447. // MyExchExt::MyExchExt()
  448. //
  449. // Parameters - none
  450. //
  451. // Purpose
  452. // Constructor. Initialize members and create supporting interface objects
  453. //
  454. // Comments
  455. // Each context of Exchange gets its own set of interface objects.
  456. // Furthermore, interface objects per context are kept track of by Exchange
  457. // and the interface methods are called in the proper context.
  458. //
  459. MyExchExt::MyExchExt (): m_cRef(1), m_context(0), m_pExchExtCommands(NULL), m_pExchExtUserEvents(NULL)
  460. {
  461. m_pExchExtCommands = new MyExchExtCommands;
  462. m_pExchExtUserEvents = new MyExchExtUserEvents;
  463. if(!m_pExchExtCommands || !m_pExchExtUserEvents)
  464. {
  465. delete m_pExchExtCommands;
  466. m_pExchExtCommands = NULL;
  467. delete m_pExchExtUserEvents;
  468. m_pExchExtUserEvents = NULL;
  469. }
  470. // in MyExchExtUserEvents methods I need a reference to MyExchExt
  471. if (m_pExchExtUserEvents)
  472. {
  473. m_pExchExtUserEvents->SetIExchExt( this );
  474. }
  475. }
  476. ///////////////////////////////////////////////////////////////////////////////
  477. // IExchExt virtual member functions implementation
  478. //
  479. ///////////////////////////////////////////////////////////////////////////////
  480. // MyExchExt::QueryInterface()
  481. //
  482. // Parameters
  483. // riid -- Interface ID.
  484. // ppvObj -- address of interface object pointer.
  485. //
  486. // Purpose
  487. // Called by Exchage to request for interfaces
  488. //
  489. // Return Value
  490. // S_OK -- interface is supported and returned in ppvObj pointer
  491. // E_NOINTERFACE -- interface is not supported and ppvObj is NULL
  492. //
  493. // Comments
  494. // Exchange client calls QueryInterface for each object. Only
  495. // Need to support objects that apply to the extension. QueryInterface
  496. // is called onces for each IID for each context. We support two
  497. // contexts in this example so QueryInterface is called twice for
  498. // each IID.
  499. //
  500. STDMETHODIMP
  501. MyExchExt::QueryInterface(
  502. REFIID riid,
  503. LPVOID * ppvObj
  504. )
  505. {
  506. HRESULT hr = S_OK;
  507. *ppvObj = NULL;
  508. if ( (IID_IUnknown == riid) || (IID_IExchExt == riid) )
  509. {
  510. *ppvObj = (LPUNKNOWN) this;
  511. }
  512. else if ( IID_IExchExtCommands == riid)
  513. {
  514. if (!m_pExchExtCommands)
  515. {
  516. hr = E_UNEXPECTED;
  517. }
  518. else
  519. {
  520. *ppvObj = (LPUNKNOWN)m_pExchExtCommands;
  521. m_pExchExtCommands->SetContext( m_context );
  522. }
  523. }
  524. else if ( IID_IExchExtUserEvents == riid)
  525. {
  526. *ppvObj = (LPUNKNOWN)m_pExchExtUserEvents;
  527. m_pExchExtUserEvents->SetContext( m_context );
  528. }
  529. else
  530. {
  531. hr = E_NOINTERFACE;
  532. }
  533. if (NULL != *ppvObj)
  534. {
  535. ((LPUNKNOWN)*ppvObj)->AddRef();
  536. }
  537. return hr;
  538. }
  539. ///////////////////////////////////////////////////////////////////////////////
  540. // MyExchExt::Install()
  541. //
  542. // Parameters
  543. // pmecb -- pointer to Exchange Extension callback function
  544. // mecontext -- context code at time of being called.
  545. // ulFlags -- flag to say if install is for modal or not
  546. //
  547. // Purpose
  548. // Called once for each new contexted that is entered. Proper version
  549. // number is checked here.
  550. //
  551. // Return Value
  552. // S_OK -- object supported in the requested context
  553. // S_FALSE -- object is not supported in teh requested context
  554. //
  555. // Comments
  556. //
  557. STDMETHODIMP
  558. MyExchExt::Install(
  559. LPEXCHEXTCALLBACK pmecb,
  560. ULONG mecontext,
  561. ULONG ulFlags
  562. )
  563. {
  564. ULONG ulBuildVersion;
  565. HRESULT hr;
  566. m_context = mecontext;
  567. // make sure this is the right version
  568. pmecb->GetVersion( &ulBuildVersion, EECBGV_GETBUILDVERSION );
  569. if (EECBGV_BUILDVERSION_MAJOR != (ulBuildVersion & EECBGV_BUILDVERSION_MAJOR_MASK)) {
  570. return S_FALSE;
  571. }
  572. switch (mecontext) {
  573. case EECONTEXT_SENDNOTEMESSAGE:
  574. hr = S_OK;
  575. break;
  576. default:
  577. hr = S_FALSE;
  578. break;
  579. }
  580. return hr;
  581. }
  582. MyExchExtCommands::MyExchExtCommands()
  583. {
  584. m_cRef = 0;
  585. m_context = 0;
  586. m_cmdid = 0;
  587. m_itbb = 0;
  588. m_itbm = 0;
  589. m_hWnd = 0;
  590. m_hwndToolbar = NULL;
  591. memset(&m_FaxConfig, 0, sizeof(m_FaxConfig));
  592. }
  593. MyExchExtCommands::~MyExchExtCommands()
  594. {
  595. MemFree( m_FaxConfig.PrinterName );
  596. MemFree( m_FaxConfig.CoverPageName );
  597. }
  598. STDMETHODIMP_(ULONG) MyExchExtCommands::AddRef()
  599. {
  600. ++m_cRef;
  601. return m_cRef;
  602. }
  603. STDMETHODIMP_(ULONG) MyExchExtCommands::Release()
  604. {
  605. ULONG ulCount = --m_cRef;
  606. if (!ulCount)
  607. {
  608. delete this;
  609. }
  610. return ulCount;
  611. }
  612. ///////////////////////////////////////////////////////////////////////////////
  613. // MyExchExtCommands::QueryInterface()
  614. //
  615. // Parameters
  616. // riid -- Interface ID.
  617. // ppvObj -- address of interface object pointer.
  618. //
  619. // Purpose
  620. // Exchange Client does not call IExchExtCommands::QueryInterface().
  621. // So return nothing.
  622. //
  623. // Return Value - none
  624. //
  625. STDMETHODIMP
  626. MyExchExtCommands::QueryInterface(
  627. REFIID riid,
  628. LPVOID FAR * ppvObj
  629. )
  630. {
  631. *ppvObj = NULL;
  632. if ( (riid == IID_IExchExtCommands) || (riid == IID_IUnknown) )
  633. {
  634. *ppvObj = (LPVOID)this;
  635. // Increase usage count of this object
  636. AddRef();
  637. return S_OK;
  638. }
  639. return E_NOINTERFACE;
  640. }
  641. ///////////////////////////////////////////////////////////////////////////////
  642. // MyExchExtCommands::InstallCommands()
  643. //
  644. // Parameters
  645. // pmecb -- Exchange Callback Interface
  646. // hWnd -- window handle to main window of context
  647. // hMenu -- menu handle to main menu of context
  648. // lptbeArray -- array of toolbar button entries
  649. // ctbe -- count of button entries in array
  650. // ulFlags -- reserved
  651. //
  652. // Purpose
  653. // This function is called when commands are installed for each context
  654. // the extension services.
  655. //
  656. // Return Value
  657. // S_FALSE means the commands have been handled.
  658. //
  659. // Comments
  660. // The hWnd and hMenu are in context. If the context is for the SENDNOTE
  661. // dialog, then the hWnd is the window handle to the dialog and the hMenu is
  662. // the main menu of the dialog.
  663. //
  664. // Call ResetToolbar so that Exchange will show it's toolbar
  665. //
  666. STDMETHODIMP
  667. MyExchExtCommands::InstallCommands(
  668. LPEXCHEXTCALLBACK pmecb,
  669. HWND hWnd,
  670. HMENU hMenu,
  671. UINT FAR * pcmdidBase,
  672. LPTBENTRY lptbeArray,
  673. UINT ctbe,
  674. ULONG ulFlags
  675. )
  676. {
  677. HRESULT hr = S_FALSE;
  678. TCHAR MenuItem[64];
  679. BOOL bResult = 0;
  680. DBG_ENTER(TEXT("MyExchExtCommands::InstallCommands"));
  681. if (m_context == EECONTEXT_SENDNOTEMESSAGE)
  682. {
  683. int tbindx;
  684. HMENU hCustomMenu;
  685. hr = pmecb->GetMenuPos( EECMDID_ToolsCustomizeToolbar, &hCustomMenu, NULL, NULL, 0);
  686. if(FAILED(hr))
  687. {
  688. CALL_FAIL(GENERAL_ERR, TEXT("pmecb->GetMenuPos"), 0);
  689. hr = S_FALSE;
  690. goto exit;
  691. }
  692. bResult = AppendMenu( hCustomMenu, MF_SEPARATOR, 0, NULL );
  693. if (!bResult)
  694. {
  695. CALL_FAIL(GENERAL_ERR, TEXT("AppendMenu"), ::GetLastError);
  696. hr = S_FALSE;
  697. goto exit;
  698. }
  699. LoadString( g_hResource, IDS_FAX_ATTRIBUTES_MENU, MenuItem, sizeof(MenuItem)/sizeof(*MenuItem));
  700. bResult = AppendMenu( hCustomMenu, MF_BYPOSITION | MF_STRING, *pcmdidBase, MenuItem );
  701. if (!bResult)
  702. {
  703. CALL_FAIL(GENERAL_ERR, TEXT("AppendMenu"), ::GetLastError);
  704. hr = S_FALSE;
  705. goto exit;
  706. }
  707. m_hWnd = hWnd;
  708. m_cmdid = *pcmdidBase;
  709. (*pcmdidBase)++;
  710. for (tbindx = ctbe-1; (int) tbindx > -1; --tbindx)
  711. {
  712. if (lptbeArray[tbindx].tbid == EETBID_STANDARD)
  713. {
  714. m_hwndToolbar = lptbeArray[tbindx].hwnd;
  715. m_itbb = lptbeArray[tbindx].itbbBase;
  716. lptbeArray[tbindx].itbbBase ++;
  717. break;
  718. }
  719. }
  720. if (m_hwndToolbar)
  721. {
  722. TBADDBITMAP tbab;
  723. tbab.hInst = g_hResource;
  724. tbab.nID = IDB_EXTBTN;
  725. m_itbm = (INT)SendMessage( m_hwndToolbar, TB_ADDBITMAP, 1, (LPARAM)&tbab );
  726. EnableMenuAndToolbar( pmecb, m_hwndToolbar, m_cmdid );
  727. ResetToolbar( EETBID_STANDARD, 0 );
  728. }
  729. hr = GetFaxConfig( pmecb, &m_FaxConfig );
  730. }
  731. exit:
  732. return hr;
  733. }
  734. ///////////////////////////////////////////////////////////////////////////////
  735. // MyExchExtCommands::DoCommand()
  736. //
  737. // Parameters
  738. // pmecb -- pointer to Exchange Callback Interface
  739. //
  740. // Purpose7
  741. // This method is called by Exchange for each WM_COMMAND is sent to the
  742. // window in context.
  743. //
  744. // Return Value
  745. // S_OK if command is handled
  746. // S_FALSE if command is not handled
  747. //
  748. // Comments
  749. // Use this function to either respond to the command item (menu or toolbar)
  750. // added or modify an existing command in Exchange. Return S_OK to let
  751. // Exchange know the command was handled. Return S_OK on commands you are
  752. // taking over from Exchange. Return S_FALSE to let Exchange know you want
  753. // it to carry out its command, even if you modify its action.
  754. //
  755. STDMETHODIMP
  756. MyExchExtCommands::DoCommand(
  757. LPEXCHEXTCALLBACK pmecb,
  758. UINT cmdid
  759. )
  760. {
  761. HRESULT hr = S_OK;
  762. HWND hwnd = NULL;
  763. INT_PTR Rslt;
  764. LPMESSAGE pMessage = NULL;
  765. LPMDB pMDB = NULL;
  766. LPSPropProblemArray lpProblems = NULL;
  767. SPropValue MsgProps[NUM_FAX_MSG_PROPS];
  768. LPSPropTagArray MsgPropTags = NULL;
  769. MAPINAMEID NameIds[NUM_FAX_MSG_PROPS];
  770. MAPINAMEID *pNameIds[NUM_FAX_MSG_PROPS] = {
  771. &NameIds[0],
  772. &NameIds[1],
  773. &NameIds[2],
  774. &NameIds[3],
  775. &NameIds[4],
  776. &NameIds[5]
  777. };
  778. LPENTRYID EntryId = NULL;
  779. DBG_ENTER(TEXT("MyExchExtCommands::DoCommand"));
  780. if (m_cmdid != cmdid)
  781. {
  782. return S_FALSE;
  783. }
  784. hr = pmecb->GetWindow( &hwnd );
  785. if (FAILED(hr))
  786. {
  787. goto exit;
  788. }
  789. Rslt = DialogBoxParam(
  790. g_hResource,
  791. MAKEINTRESOURCE(FAX_CONFIG_DIALOG),
  792. hwnd,
  793. ConfigDlgProc,
  794. (LPARAM) &m_FaxConfig
  795. );
  796. if (Rslt == IDOK)
  797. {
  798. hr = pmecb->GetObject( &pMDB, (LPMAPIPROP *) &pMessage );
  799. if (FAILED(hr)) {
  800. goto exit;
  801. }
  802. NameIds[MSGPI_FAX_PRINTER_NAME].lpguid = (LPGUID)&PS_PUBLIC_STRINGS;
  803. NameIds[MSGPI_FAX_PRINTER_NAME].ulKind = MNID_STRING;
  804. NameIds[MSGPI_FAX_PRINTER_NAME].Kind.lpwstrName = MSGPS_FAX_PRINTER_NAME;
  805. NameIds[MSGPI_FAX_COVERPAGE_NAME].lpguid = (LPGUID)&PS_PUBLIC_STRINGS;
  806. NameIds[MSGPI_FAX_COVERPAGE_NAME].ulKind = MNID_STRING;
  807. NameIds[MSGPI_FAX_COVERPAGE_NAME].Kind.lpwstrName = MSGPS_FAX_COVERPAGE_NAME;
  808. NameIds[MSGPI_FAX_USE_COVERPAGE].lpguid = (LPGUID)&PS_PUBLIC_STRINGS;
  809. NameIds[MSGPI_FAX_USE_COVERPAGE].ulKind = MNID_STRING;
  810. NameIds[MSGPI_FAX_USE_COVERPAGE].Kind.lpwstrName = MSGPS_FAX_USE_COVERPAGE;
  811. NameIds[MSGPI_FAX_SERVER_COVERPAGE].lpguid = (LPGUID)&PS_PUBLIC_STRINGS;
  812. NameIds[MSGPI_FAX_SERVER_COVERPAGE].ulKind = MNID_STRING;
  813. NameIds[MSGPI_FAX_SERVER_COVERPAGE].Kind.lpwstrName = MSGPS_FAX_SERVER_COVERPAGE;
  814. NameIds[MSGPI_FAX_SEND_SINGLE_RECEIPT].lpguid = (LPGUID)&PS_PUBLIC_STRINGS;
  815. NameIds[MSGPI_FAX_SEND_SINGLE_RECEIPT].ulKind = MNID_STRING;
  816. NameIds[MSGPI_FAX_SEND_SINGLE_RECEIPT].Kind.lpwstrName = MSGPS_FAX_SEND_SINGLE_RECEIPT;
  817. NameIds[MSGPI_FAX_ATTACH_FAX].lpguid = (LPGUID)&PS_PUBLIC_STRINGS;
  818. NameIds[MSGPI_FAX_ATTACH_FAX].ulKind = MNID_STRING;
  819. NameIds[MSGPI_FAX_ATTACH_FAX].Kind.lpwstrName = MSGPS_FAX_ATTACH_FAX;
  820. hr = pMessage->GetIDsFromNames( NUM_FAX_MSG_PROPS, pNameIds, MAPI_CREATE, &MsgPropTags );
  821. if (FAILED(hr)) {
  822. goto exit;
  823. }
  824. MsgPropTags->aulPropTag[MSGPI_FAX_PRINTER_NAME] = PROP_TAG( PT_BINARY, PROP_ID(MsgPropTags->aulPropTag[MSGPI_FAX_PRINTER_NAME]) );
  825. MsgPropTags->aulPropTag[MSGPI_FAX_COVERPAGE_NAME] = PROP_TAG( PT_BINARY, PROP_ID(MsgPropTags->aulPropTag[MSGPI_FAX_COVERPAGE_NAME]) );
  826. MsgPropTags->aulPropTag[MSGPI_FAX_USE_COVERPAGE] = PROP_TAG( PT_LONG, PROP_ID(MsgPropTags->aulPropTag[MSGPI_FAX_USE_COVERPAGE]) );
  827. MsgPropTags->aulPropTag[MSGPI_FAX_SERVER_COVERPAGE] = PROP_TAG( PT_LONG, PROP_ID(MsgPropTags->aulPropTag[MSGPI_FAX_SERVER_COVERPAGE]) );
  828. MsgPropTags->aulPropTag[MSGPI_FAX_SEND_SINGLE_RECEIPT] = PROP_TAG( PT_LONG, PROP_ID(MsgPropTags->aulPropTag[MSGPI_FAX_SEND_SINGLE_RECEIPT]) );
  829. MsgPropTags->aulPropTag[MSGPI_FAX_ATTACH_FAX] = PROP_TAG( PT_LONG, PROP_ID(MsgPropTags->aulPropTag[MSGPI_FAX_ATTACH_FAX]) );
  830. MsgProps[MSGPI_FAX_PRINTER_NAME].ulPropTag = MsgPropTags->aulPropTag[MSGPI_FAX_PRINTER_NAME];
  831. MsgProps[MSGPI_FAX_COVERPAGE_NAME].ulPropTag = MsgPropTags->aulPropTag[MSGPI_FAX_COVERPAGE_NAME];
  832. MsgProps[MSGPI_FAX_USE_COVERPAGE].ulPropTag = MsgPropTags->aulPropTag[MSGPI_FAX_USE_COVERPAGE];
  833. MsgProps[MSGPI_FAX_SERVER_COVERPAGE].ulPropTag = MsgPropTags->aulPropTag[MSGPI_FAX_SERVER_COVERPAGE];
  834. MsgProps[MSGPI_FAX_SEND_SINGLE_RECEIPT].ulPropTag = MsgPropTags->aulPropTag[MSGPI_FAX_SEND_SINGLE_RECEIPT];
  835. MsgProps[MSGPI_FAX_ATTACH_FAX].ulPropTag = MsgPropTags->aulPropTag[MSGPI_FAX_ATTACH_FAX];
  836. MsgProps[MSGPI_FAX_PRINTER_NAME].Value.bin.cb = (_tcslen(m_FaxConfig.PrinterName) + 1) * sizeof(TCHAR);
  837. MsgProps[MSGPI_FAX_PRINTER_NAME].Value.bin.lpb = (LPBYTE )StringDup(m_FaxConfig.PrinterName);
  838. if(!MsgProps[MSGPI_FAX_PRINTER_NAME].Value.bin.lpb)
  839. {
  840. MsgProps[MSGPI_FAX_PRINTER_NAME].Value.bin.cb = 0;
  841. CALL_FAIL(MEM_ERR, TEXT("StringDup"), ERROR_NOT_ENOUGH_MEMORY);
  842. ErrorMsgBox(g_hResource, hwnd, IDS_NOT_ENOUGH_MEMORY);
  843. hr = E_OUTOFMEMORY;
  844. goto exit;
  845. }
  846. MsgProps[MSGPI_FAX_COVERPAGE_NAME].Value.bin.cb =( _tcslen(m_FaxConfig.CoverPageName) + 1) * sizeof(TCHAR);
  847. MsgProps[MSGPI_FAX_COVERPAGE_NAME].Value.bin.lpb = (LPBYTE)StringDup(m_FaxConfig.CoverPageName);
  848. if(!MsgProps[MSGPI_FAX_COVERPAGE_NAME].Value.bin.lpb)
  849. {
  850. MsgProps[MSGPI_FAX_COVERPAGE_NAME].Value.bin.cb = 0;
  851. CALL_FAIL(MEM_ERR, TEXT("StringDup"), ERROR_NOT_ENOUGH_MEMORY);
  852. ErrorMsgBox(g_hResource, hwnd, IDS_NOT_ENOUGH_MEMORY);
  853. hr = E_OUTOFMEMORY;
  854. goto exit;
  855. }
  856. MsgProps[MSGPI_FAX_USE_COVERPAGE].Value.ul = m_FaxConfig.UseCoverPage;
  857. MsgProps[MSGPI_FAX_SERVER_COVERPAGE].Value.ul = m_FaxConfig.ServerCoverPage;
  858. MsgProps[MSGPI_FAX_SEND_SINGLE_RECEIPT].Value.ul = m_FaxConfig.SendSingleReceipt;
  859. MsgProps[MSGPI_FAX_ATTACH_FAX].Value.ul = m_FaxConfig.bAttachFax;
  860. hr = pMessage->SetProps( NUM_FAX_MSG_PROPS, MsgProps, &lpProblems );
  861. if (FAILED(hr)) {
  862. goto exit;
  863. }
  864. if (lpProblems) {
  865. hr = MAPI_E_NOT_FOUND;
  866. goto exit;
  867. }
  868. }
  869. exit:
  870. if (MsgPropTags)
  871. {
  872. MAPIFreeBuffer ( MsgPropTags );
  873. }
  874. if (lpProblems)
  875. {
  876. MAPIFreeBuffer ( lpProblems );
  877. }
  878. if (pMessage)
  879. {
  880. pMessage->Release();
  881. }
  882. if (pMDB)
  883. {
  884. pMDB->Release();
  885. }
  886. return hr;
  887. }
  888. ///////////////////////////////////////////////////////////////////////////////
  889. // MyExchExtCommands::InitMenu()
  890. //
  891. // Parameters
  892. // pmecb -- pointer to Exchange Callback Interface
  893. //
  894. // Purpose
  895. // This method is called by Exchange when the menu of context is about to
  896. // be activated. See WM_INITMENU in the Windows API Reference for more
  897. // information.
  898. //
  899. // Return Value - none
  900. //
  901. STDMETHODIMP_(VOID)
  902. MyExchExtCommands::InitMenu(
  903. LPEXCHEXTCALLBACK pmecb
  904. )
  905. {
  906. return;
  907. }
  908. ///////////////////////////////////////////////////////////////////////////////
  909. // MyExchExtCommands::Help()
  910. //
  911. // Parameters
  912. // pmecb -- pointer to Exchange Callback Interface
  913. // cmdid -- command id
  914. //
  915. // Purpose
  916. // Respond when user presses F1 while custom menu item is selected.
  917. //
  918. // Return Value
  919. // S_OK -- recognized the command and provided help
  920. // S_FALSE -- not our command and we didn't provide help
  921. //
  922. STDMETHODIMP MyExchExtCommands::Help(
  923. LPEXCHEXTCALLBACK pmecb,
  924. UINT cmdid
  925. )
  926. {
  927. return S_FALSE;
  928. }
  929. ///////////////////////////////////////////////////////////////////////////////
  930. // MyExchExtCommands::QueryHelpText()
  931. //
  932. // Parameters
  933. // cmdid -- command id corresponding to menu item activated
  934. // ulFlags -- identifies either EECQHT_STATUS or EECQHT_TOOLTIP
  935. // psz -- pointer to buffer to be populated with text to display
  936. // cch -- count of characters available in psz buffer
  937. //
  938. // Purpose
  939. // Exchange calls this function each time it requires to update the status
  940. // bar text or if it is to display a tooltip on the toolbar.
  941. //
  942. // Return Value
  943. // S_OK to indicate our command was handled
  944. // S_FALSE to tell Exchange it can continue with its function
  945. //
  946. STDMETHODIMP
  947. MyExchExtCommands::QueryHelpText(
  948. UINT cmdid,
  949. ULONG ulFlags,
  950. LPTSTR psz,
  951. UINT cch
  952. )
  953. {
  954. HRESULT hr;
  955. TCHAR HelpText[64];
  956. LoadString(g_hResource,IDS_FAX_ATTRIBUTES_TOOLTIP,HelpText,sizeof(HelpText)/sizeof(*HelpText));
  957. if (cmdid == m_cmdid)
  958. {
  959. if (ulFlags == EECQHT_STATUS)
  960. {
  961. _tcsncpy(psz,HelpText,cch/sizeof(TCHAR));
  962. }
  963. if (ulFlags == EECQHT_TOOLTIP)
  964. {
  965. _tcsncpy(psz,HelpText,cch/sizeof(TCHAR));
  966. }
  967. hr = S_OK;
  968. }
  969. else
  970. {
  971. hr = S_FALSE;
  972. }
  973. return hr;
  974. }
  975. ///////////////////////////////////////////////////////////////////////////////
  976. // MyExchExtCommands::QueryButtonInfo()
  977. //
  978. // Parameters
  979. // tbid -- toolbar identifier
  980. // itbb -- toolbar button index
  981. // ptbb -- pointer to toolbar button structure -- see TBBUTTON structure
  982. // lpsz -- point to string describing button
  983. // cch -- maximum size of lpsz buffer
  984. // ulFlags -- EXCHEXT_UNICODE may be specified
  985. //
  986. // Purpose
  987. // For Exchange to find out about toolbar button information.
  988. //
  989. // Return Value
  990. // S_FALSE - not our button
  991. // S_OK - we filled information about our button
  992. //
  993. // Comments
  994. // Called for every button installed for toolbars when IExchExtCommands
  995. // is installed for each context. The lpsz text is used when the Customize
  996. // Toolbar dialog is displayed. The text will be displayed next to the
  997. // button.
  998. //
  999. STDMETHODIMP MyExchExtCommands::QueryButtonInfo(
  1000. ULONG tbid,
  1001. UINT itbb,
  1002. LPTBBUTTON ptbb,
  1003. LPTSTR lpsz,
  1004. UINT cch,
  1005. ULONG ulFlags
  1006. )
  1007. {
  1008. HRESULT hr = S_FALSE;
  1009. TCHAR CustText[64];
  1010. LoadString(g_hResource,IDS_FAX_ATTRIBUTES_CUST,CustText,sizeof(CustText)/sizeof(TCHAR));
  1011. if (m_itbb == itbb) {
  1012. ptbb->iBitmap = m_itbm;
  1013. ptbb->idCommand = m_cmdid;
  1014. ptbb->fsState = TBSTATE_ENABLED;
  1015. ptbb->fsStyle = TBSTYLE_BUTTON;
  1016. ptbb->dwData = 0;
  1017. ptbb->iString = -1;
  1018. _tcsncpy(lpsz,CustText,cch/sizeof(TCHAR));
  1019. hr = S_OK;
  1020. }
  1021. return hr;
  1022. }
  1023. ///////////////////////////////////////////////////////////////////////////////
  1024. // MyExchExtCommands::ResetToolbar()
  1025. //
  1026. // Parameters
  1027. // tbid
  1028. // ulFlags
  1029. //
  1030. // Purpose
  1031. //
  1032. // Return Value S_OK always
  1033. //
  1034. STDMETHODIMP
  1035. MyExchExtCommands::ResetToolbar(
  1036. ULONG tbid,
  1037. ULONG ulFlags
  1038. )
  1039. {
  1040. return S_OK;
  1041. }
  1042. ///////////////////////////////////////////////////////////////////////////////
  1043. // IExchExtUserEvents virtual member functions implementation
  1044. //
  1045. ///////////////////////////////////////////////////////////////////////////////
  1046. // MyExchExtUserEvents::QueryInterface()
  1047. //
  1048. // Parameters
  1049. // riid -- Interface ID.
  1050. // ppvObj -- address of interface object pointer.
  1051. //
  1052. // Purpose
  1053. // Exchange Client does not call IExchExtUserEvents::QueryInterface().
  1054. // So return nothing.
  1055. //
  1056. // Return Value - none
  1057. //
  1058. STDMETHODIMP
  1059. MyExchExtUserEvents::QueryInterface(
  1060. REFIID riid,
  1061. LPVOID FAR * ppvObj
  1062. )
  1063. {
  1064. *ppvObj = NULL;
  1065. if (( riid == IID_IExchExtUserEvents) || (riid == IID_IUnknown) ) {
  1066. *ppvObj = (LPVOID)this;
  1067. // Increase usage count of this object
  1068. AddRef();
  1069. return S_OK;
  1070. }
  1071. return E_NOINTERFACE;
  1072. }
  1073. ///////////////////////////////////////////////////////////////////////////////
  1074. // MyExchExtUserEvents::OnSelectionChange()
  1075. //
  1076. // Parameters
  1077. // pmecb -- pointer to Exchange Callback Object
  1078. //
  1079. //
  1080. // Purpose
  1081. // This function is called when the selection in the UI is changed.
  1082. //
  1083. // Return Value - none
  1084. //
  1085. // Comments
  1086. // OnSelectionChange is called whenever the selection changes either within
  1087. // a pane or is changed between panes.
  1088. //
  1089. STDMETHODIMP_(VOID)
  1090. MyExchExtUserEvents::OnSelectionChange(
  1091. LPEXCHEXTCALLBACK pmecb
  1092. )
  1093. {
  1094. }
  1095. ///////////////////////////////////////////////////////////////////////////////
  1096. // MyExchExtUserEvents::OnObjectChange()
  1097. //
  1098. // Parameters
  1099. // pmecb -- pointer to Exchange Callback Object
  1100. //
  1101. //
  1102. // Purpose
  1103. // This function is called when the selection in the UI is to a different
  1104. // of object on the left pane.
  1105. //
  1106. // Return Value - none
  1107. //
  1108. // Comments
  1109. // OnObjectChange is called whenever the selection is changed between
  1110. // objects in the left pane only. Change in selection between folders,
  1111. // subfolders or container object in the left pane will be reflected with a
  1112. // call to OnObjectChange. Change in selection between objects (messages,
  1113. // subfolders) in the right pane will not call OnObjectChange, only
  1114. // OnSelectionChange.
  1115. //
  1116. STDMETHODIMP_(VOID)
  1117. MyExchExtUserEvents::OnObjectChange(
  1118. LPEXCHEXTCALLBACK pmecb
  1119. )
  1120. {
  1121. }
  1122. BOOL
  1123. GetServerNameFromPrinterName(
  1124. LPTSTR lptszPrinterName,
  1125. LPTSTR *pptszServerName
  1126. )
  1127. /*++
  1128. Routine Description:
  1129. retrieve the server name given a printer name
  1130. Arguments:
  1131. [in] lptszPrinterName - Identifies the printer in question
  1132. [out] lptszServerName - Address of pointer to output string buffer.
  1133. NULL indicates local server.
  1134. The caller is responsible to free the buffer which
  1135. pointer is given in this parameter.
  1136. Return Value:
  1137. BOOL: TRUE - operation succeeded , FALSE: failed
  1138. --*/
  1139. {
  1140. PPRINTER_INFO_2 ppi2 = NULL;
  1141. LPTSTR lptstrBuffer = NULL;
  1142. BOOL bRes = FALSE;
  1143. if (lptszPrinterName)
  1144. {
  1145. if (ppi2 = (PPRINTER_INFO_2) MyGetPrinter(lptszPrinterName,2))
  1146. {
  1147. if (GetServerNameFromPrinterInfo(ppi2,&lptstrBuffer))
  1148. {
  1149. if (lptstrBuffer)
  1150. {
  1151. bRes = (NULL != (*pptszServerName = StringDup(lptstrBuffer)));
  1152. }
  1153. else
  1154. {
  1155. bRes = TRUE;
  1156. }
  1157. }
  1158. MemFree(ppi2);
  1159. }
  1160. }
  1161. return bRes;
  1162. }