Source code of Windows XP (NT5)
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.

1676 lines
36 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. util.c
  5. Abstract:
  6. Misc. utility functions used by the fax configuration applet
  7. Environment:
  8. Fax configuration applet
  9. Revision History:
  10. 03/13/96 -davidx-
  11. Created it.
  12. mm/dd/yy -author-
  13. description
  14. --*/
  15. #include "faxcpl.h"
  16. #include "forms.h"
  17. #include "cfghelp.h"
  18. #include <shlobj.h>
  19. #include <mapicode.h>
  20. #include <winsprlp.h>
  21. //
  22. // A flag to indicate whether we're inside SetDlgItemText call.
  23. // This is a kluge but we have no other way of telling whether
  24. // an EN_CHANGE message is caused by user action or by us calling
  25. // SetDlgItemText.
  26. //
  27. BOOL insideSetDlgItemText = FALSE;
  28. VOID
  29. SetChangedFlag(
  30. HWND hDlg,
  31. INT pageIndex,
  32. BOOL changed
  33. )
  34. /*++
  35. Routine Description:
  36. Enable or disable the Apply button in the property sheet
  37. depending on if any of the dialog contents was changed
  38. Arguments:
  39. hDlg - Handle to the property page window
  40. pageIndex - Specifies the index of current property page
  41. changed - Specifies whether the Apply button should be enabled
  42. Return Value:
  43. NONE
  44. --*/
  45. {
  46. HWND hwndPropSheet;
  47. INT pageMask = (1 << pageIndex);
  48. //
  49. // Enable or disable the Apply button as appropriate
  50. //
  51. hwndPropSheet = GetParent(hDlg);
  52. if (changed) {
  53. PropSheet_Changed(hwndPropSheet, hDlg);
  54. gConfigData->changeFlag |= pageMask;
  55. } else {
  56. gConfigData->changeFlag &= ~pageMask;
  57. if (gConfigData->changeFlag == 0) {
  58. PropSheet_UnChanged(hwndPropSheet, hDlg);
  59. }
  60. }
  61. }
  62. BOOL
  63. GetMapiProfiles(
  64. VOID
  65. )
  66. /*++
  67. Routine Description:
  68. Connect to the server and get its MAPI profiles.
  69. Arguments:
  70. NONE
  71. Return Value:
  72. TRUE if successful, FALSE if not
  73. --*/
  74. {
  75. if (gConfigData->pMapiProfiles)
  76. return TRUE;
  77. if (!FaxGetMapiProfiles(gConfigData->hFaxSvc, (LPBYTE*) &gConfigData->pMapiProfiles))
  78. {
  79. gConfigData->pMapiProfiles = NULL;
  80. Error(("Cannot retrieve MapiProfiles: %d\n", GetLastError()));
  81. return FALSE;
  82. }
  83. return TRUE;
  84. }
  85. PVOID
  86. MyEnumPrinters(
  87. LPTSTR pServerName,
  88. DWORD level,
  89. PDWORD pcPrinters,
  90. DWORD dwFlags
  91. )
  92. /*++
  93. Routine Description:
  94. Wrapper function for spooler API EnumPrinters
  95. Arguments:
  96. pServerName - Specifies the name of the print server
  97. level - Level of PRINTER_INFO_x structure
  98. pcPrinters - Returns the number of printers enumerated
  99. dwFlags - Flag bits passed to EnumPrinters
  100. Return Value:
  101. Pointer to an array of PRINTER_INFO_x structures
  102. NULL if there is an error
  103. --*/
  104. {
  105. PBYTE pPrinterInfo = NULL;
  106. DWORD cb;
  107. if (! EnumPrinters(dwFlags, pServerName, level, NULL, 0, &cb, pcPrinters) &&
  108. GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
  109. (pPrinterInfo = MemAlloc(cb)) &&
  110. EnumPrinters(dwFlags, pServerName, level, pPrinterInfo, cb, &cb, pcPrinters))
  111. {
  112. return pPrinterInfo;
  113. }
  114. Error(("EnumPrinters failed: %d\n", GetLastError()));
  115. MemFree(pPrinterInfo);
  116. return NULL;
  117. }
  118. LPTSTR
  119. MakePortNameString(
  120. VOID
  121. )
  122. /*++
  123. Routine Description:
  124. Compose a port name string consisting of all available fax devices
  125. Arguments:
  126. NONE
  127. Return Value:
  128. Pointer to a list of comma-separated port names
  129. NULL if there is an error
  130. --*/
  131. {
  132. LPTSTR pPortName, p;
  133. INT index, cb;
  134. //
  135. // Connect to the fax service and retrieve the list of fax devices
  136. //
  137. GetFaxDeviceAndConfigInfo();
  138. //
  139. // Figure out the total size of port name string
  140. //
  141. for (index=cb=0; index < gConfigData->cDevices; index++)
  142. cb += SizeOfString(gConfigData->pDevInfo[index].DeviceName);
  143. if (cb == 0 || !(p = pPortName = MemAlloc(cb)))
  144. return NULL;
  145. //
  146. // Compose the port name string
  147. //
  148. for (index=0; index < gConfigData->cDevices; index++) {
  149. if (p != pPortName)
  150. *p++ = PORTNAME_SEPARATOR;
  151. _tcscpy(p, gConfigData->pDevInfo[index].DeviceName);
  152. p += _tcslen(p);
  153. }
  154. return pPortName;
  155. }
  156. BOOL
  157. CheckFaxServerType(
  158. HWND hDlg,
  159. LPTSTR pPrinterName
  160. )
  161. /*++
  162. Routine Description:
  163. Make sure the print server has fax server software installed
  164. Arguments:
  165. hDlg - Handle to the currently active property page
  166. pPrinterName - Specifies the name of the shared printer
  167. Return Value:
  168. TRUE if the fax server software is installed
  169. FALSE otherwise
  170. --*/
  171. {
  172. HANDLE hServer;
  173. LPTSTR p, pNoRemoteDrivers;
  174. INT status = 0;
  175. //
  176. // Derived the server name from the share name
  177. //
  178. Assert(_tcsncmp(pPrinterName, TEXT("\\\\"), 2) == EQUAL_STRING);
  179. p = pPrinterName + 2;
  180. if (p = _tcschr(p, TEXT(PATH_SEPARATOR))) {
  181. *p = NUL;
  182. if (OpenPrinter(pPrinterName, &hServer, NULL)) {
  183. if (pNoRemoteDrivers = GetPrinterDataStr(hServer, SPLREG_NO_REMOTE_PRINTER_DRIVERS)) {
  184. if (_tcsstr(pNoRemoteDrivers, DRIVER_NAME) != NULL)
  185. status = IDS_NO_FAXSERVER;
  186. MemFree(pNoRemoteDrivers);
  187. }
  188. ClosePrinter(hServer);
  189. } else
  190. status = IDS_SERVER_NOTALIVE;
  191. *p = TEXT(PATH_SEPARATOR);
  192. } else
  193. status = IDS_INVALID_SHARENAME;
  194. if (status != 0)
  195. DisplayMessageDialog(hDlg, 0, 0, status);
  196. return (status == 0);
  197. }
  198. PVOID
  199. FaxSvcEnumPorts(
  200. HANDLE hFaxSvc,
  201. PDWORD pcPorts
  202. )
  203. /*++
  204. Routine Description:
  205. Wrapper function for fax service API FaxEnumPorts
  206. Arguments:
  207. hFaxSvc - Specifies a coneection handle to the fax service
  208. DWORD - Specifies the level of FAX_PORT_INFO structure desired
  209. pcPorts - Returns the number of devices managed by the fax service
  210. Return Value:
  211. Pointer to an array of FAX_PORT_INFO_x structures
  212. NULL if there is an error
  213. --*/
  214. {
  215. PVOID pSvcPortInfo = NULL;
  216. if (!FaxEnumPorts(hFaxSvc, (PFAX_PORT_INFO*) &pSvcPortInfo, pcPorts)) {
  217. Error(("FaxEnumPorts failed: %d\n", GetLastError()));
  218. return NULL;
  219. }
  220. return pSvcPortInfo;
  221. }
  222. BOOL
  223. GetFaxDeviceAndConfigInfo(
  224. VOID
  225. )
  226. /*++
  227. Routine Description:
  228. Get a list of fax devices available on the system and
  229. retrieve fax configuration information from the service
  230. Arguments:
  231. NONE
  232. Return Value:
  233. TRUE if successful, FALSE if there is an error
  234. --*/
  235. {
  236. PFAX_PORT_INFO pSvcPortInfo;
  237. PFAX_PORT_INFO pSvcPort;
  238. PCONFIG_PORT_INFO_2 pDevInfo;
  239. DWORD index;
  240. DWORD cPorts;
  241. DWORD cb;
  242. HANDLE FaxPortHandle;
  243. LPBYTE RoutingInfo;
  244. Verbose(("Enumerating fax ports ...\n"));
  245. Assert(ValidConfigData(gConfigData));
  246. if (gConfigData->pDevInfo)
  247. return TRUE;
  248. //
  249. // Allocate memory to hold information about fax devices
  250. //
  251. Assert(gConfigData->hFaxSvc != NULL);
  252. Assert(gConfigData->cDevices == 0);
  253. if (! (pSvcPortInfo = FaxSvcEnumPorts(gConfigData->hFaxSvc, &cPorts)) ||
  254. ! (gConfigData->pDevInfo = pDevInfo = MemAllocZ(sizeof(CONFIG_PORT_INFO_2) * cPorts)))
  255. {
  256. FaxFreeBuffer(pSvcPortInfo);
  257. return FALSE;
  258. }
  259. //
  260. // Collect information about each fax device. Here we're depending on the fact that
  261. // fax devices are enumerated in reverse priority order, i.e. the lowest priority
  262. // device is enumerated first.
  263. //
  264. Verbose(("Available fax devices:\n"));
  265. for (index=0; index < cPorts; index++, pDevInfo++) {
  266. pSvcPort = &pSvcPortInfo[cPorts - index - 1];
  267. Verbose(( " %ws\n", pSvcPort->DeviceName ));
  268. pDevInfo->SizeOfStruct = pSvcPort->SizeOfStruct;
  269. pDevInfo->DeviceId = pSvcPort->DeviceId;
  270. pDevInfo->State = pSvcPort->State;
  271. pDevInfo->Flags = pSvcPort->Flags;
  272. pDevInfo->Rings = pSvcPort->Rings;
  273. pDevInfo->Priority = pSvcPort->Priority;
  274. pDevInfo->DeviceName = DuplicateString( pSvcPort->DeviceName );
  275. pDevInfo->CSID = DuplicateString( pSvcPort->Csid);
  276. pDevInfo->TSID = DuplicateString( pSvcPort->Tsid);
  277. pDevInfo->Mask = 0;
  278. pDevInfo->ProfileName = NULL;
  279. pDevInfo->PrinterName = NULL;
  280. pDevInfo->DirStore = NULL;
  281. //
  282. // open the fax port for query so we can get the routing info
  283. //
  284. if (FaxOpenPort(gConfigData->hFaxSvc, pDevInfo->DeviceId, PORT_OPEN_QUERY, &FaxPortHandle )) {
  285. //
  286. // get the store dir
  287. //
  288. if (FaxGetRoutingInfo( FaxPortHandle, REGVAL_RM_FOLDER_GUID, &RoutingInfo, &cb )) {
  289. if (*((LPDWORD)RoutingInfo)) {
  290. pDevInfo->Mask |= LR_STORE;
  291. pDevInfo->DirStore = DuplicateString( (LPWSTR)(RoutingInfo+sizeof(DWORD)) );
  292. }
  293. FaxFreeBuffer( RoutingInfo );
  294. }
  295. //
  296. // get the printer name
  297. //
  298. if (FaxGetRoutingInfo( FaxPortHandle, REGVAL_RM_PRINTING_GUID, &RoutingInfo, &cb )) {
  299. if (*((LPDWORD)RoutingInfo)) {
  300. pDevInfo->Mask |= LR_PRINT;
  301. pDevInfo->PrinterName = DuplicateString( (LPWSTR)(RoutingInfo+sizeof(DWORD)) );
  302. }
  303. FaxFreeBuffer( RoutingInfo );
  304. }
  305. //
  306. // get the email profile name
  307. //
  308. if (FaxGetRoutingInfo( FaxPortHandle, REGVAL_RM_EMAIL_GUID, &RoutingInfo, &cb )) {
  309. if (*((LPDWORD)RoutingInfo)) {
  310. pDevInfo->Mask |= LR_EMAIL;
  311. pDevInfo->ProfileName = DuplicateString( (LPWSTR)(RoutingInfo+sizeof(DWORD)) );
  312. }
  313. FaxFreeBuffer( RoutingInfo );
  314. }
  315. //
  316. // get the inbox profile name
  317. //
  318. if (FaxGetRoutingInfo( FaxPortHandle, REGVAL_RM_INBOX_GUID, &RoutingInfo, &cb )) {
  319. if (*((LPDWORD)RoutingInfo)) {
  320. pDevInfo->Mask |= LR_INBOX;
  321. MemFree( pDevInfo->ProfileName );
  322. pDevInfo->ProfileName = DuplicateString( (LPWSTR)(RoutingInfo+sizeof(DWORD)) );
  323. }
  324. FaxFreeBuffer( RoutingInfo );
  325. }
  326. FaxClose( FaxPortHandle );
  327. }
  328. gConfigData->cDevices++;
  329. }
  330. //
  331. // Retrieve fax configuration information from the service
  332. //
  333. Assert( gConfigData->pFaxConfig == NULL );
  334. if (!FaxGetConfiguration(gConfigData->hFaxSvc, &gConfigData->pFaxConfig)) {
  335. Error(("Cannot retrieve fax configuration information: %d\n", GetLastError()));
  336. gConfigData->pFaxConfig = NULL;
  337. }
  338. //
  339. // Retrieve the logging categories
  340. //
  341. Assert( gConfigData->pFaxLogging == NULL );
  342. if (!FaxGetLoggingCategories( gConfigData->hFaxSvc, &gConfigData->pFaxLogging, &gConfigData->NumberCategories )) {
  343. Error(("Cannot retrieve fax logging category information: %d\n", GetLastError()));
  344. gConfigData->pFaxLogging = NULL;
  345. }
  346. }
  347. BOOL
  348. SaveFaxDeviceAndConfigInfo(
  349. HWND hDlg,
  350. INT pageIndex
  351. )
  352. /*++
  353. Routine Description:
  354. Save fax device and configuration information
  355. Arguments:
  356. hDlg - Handle to the currently active property page
  357. pageIndex - Specifies the currently active page index
  358. Return Value:
  359. TRUE if successful, FALSE if there is an error
  360. --*/
  361. #define FAIL_SAVE_FAX_CONFIG(err) { errorId = err; goto ExitSaveFaxConfig; }
  362. {
  363. PCONFIG_PORT_INFO_2 pDevInfo;
  364. FAX_PORT_INFO SvcPort;
  365. DWORD ec;
  366. INT index = 0;
  367. INT errorId = 0;
  368. DWORD cb;
  369. //
  370. // Check if we're on the last page that has settable fax configuration info
  371. //
  372. if ((gConfigData->changeFlag & CONFIGPAGE_MASK) != (1 << pageIndex)) {
  373. return TRUE;
  374. }
  375. if (gConfigData->hFaxSvc == NULL) {
  376. FAIL_SAVE_FAX_CONFIG(IDS_NULL_SERVICE_HANDLE);
  377. }
  378. //
  379. // Save fax configuration information
  380. //
  381. if (gConfigData->pFaxConfig &&
  382. ! FaxSetConfiguration(gConfigData->hFaxSvc, gConfigData->pFaxConfig))
  383. {
  384. ec = GetLastError();
  385. Error(("FaxSetConfiguration failed: %d\n", ec));
  386. FAIL_SAVE_FAX_CONFIG((ec == ERROR_ACCESS_DENIED ? IDS_NO_AUTHORITY : IDS_FAXSETCONFIG_FAILED));
  387. }
  388. //
  389. // Save fax device information
  390. // NOTE: Here, we're calling FaxSetPort on every device which may be
  391. // a little redundant. But it shouldn't hurt anything.
  392. //
  393. pDevInfo = gConfigData->pDevInfo;
  394. for (index=0; index < gConfigData->cDevices; index++, pDevInfo++) {
  395. HANDLE FaxPortHandle;
  396. LPBYTE RoutingInfo;
  397. if (!FaxOpenPort(gConfigData->hFaxSvc, pDevInfo->DeviceId, PORT_OPEN_MODIFY, &FaxPortHandle )) {
  398. DisplayMessageDialog(hDlg, 0, 0, IDS_DEVICE_BUSY, pDevInfo->DeviceName);
  399. return FALSE;
  400. }
  401. SvcPort.SizeOfStruct = pDevInfo->SizeOfStruct;
  402. SvcPort.DeviceId = pDevInfo->DeviceId;
  403. SvcPort.State = pDevInfo->State;
  404. SvcPort.Flags = pDevInfo->Flags;
  405. SvcPort.Rings = pDevInfo->Rings;
  406. SvcPort.Priority = pDevInfo->Priority;
  407. SvcPort.DeviceName = pDevInfo->DeviceName;
  408. SvcPort.Tsid = pDevInfo->TSID;
  409. SvcPort.Csid = pDevInfo->CSID;
  410. if (! FaxSetPort(FaxPortHandle, &SvcPort)) {
  411. ec = GetLastError();
  412. Error(("FaxSetPort failed: %d\n", ec));
  413. FAIL_SAVE_FAX_CONFIG((ec == ERROR_ACCESS_DENIED ? IDS_NO_AUTHORITY : IDS_FAXSETPORT_FAILED));
  414. }
  415. //
  416. // change the routing information
  417. //
  418. cb = 4096;
  419. RoutingInfo = (LPBYTE) MemAllocZ( cb );
  420. if (!RoutingInfo) {
  421. Error(("Memory allocation failed: %d\n", GetLastError()));
  422. goto ExitSaveFaxConfig;
  423. }
  424. //
  425. // set the store dir
  426. //
  427. *((LPDWORD)RoutingInfo) = (pDevInfo->Mask & LR_STORE) > 0;
  428. if (pDevInfo->Mask & LR_STORE) {
  429. _tcscpy( (LPTSTR) (RoutingInfo+sizeof(DWORD)), pDevInfo->DirStore );
  430. }
  431. if (!FaxSetRoutingInfo( FaxPortHandle, REGVAL_RM_FOLDER_GUID, RoutingInfo, cb )) {
  432. Error(("FaxSetRoutingInfo failed: %d\n", GetLastError()));
  433. }
  434. //
  435. // set the printer name
  436. //
  437. *((LPDWORD)RoutingInfo) = (pDevInfo->Mask & LR_PRINT) > 0;
  438. if (pDevInfo->Mask & LR_PRINT) {
  439. _tcscpy( (LPTSTR) (RoutingInfo+sizeof(DWORD)), pDevInfo->PrinterName ? pDevInfo->PrinterName : TEXT("") );
  440. }
  441. if (!FaxSetRoutingInfo( FaxPortHandle, REGVAL_RM_PRINTING_GUID, RoutingInfo, cb )) {
  442. Error(("FaxSetRoutingInfo failed: %d\n", GetLastError()));
  443. }
  444. //
  445. // set the email profile name
  446. //
  447. *((LPDWORD)RoutingInfo) = (pDevInfo->Mask & LR_EMAIL) > 0;
  448. if (pDevInfo->Mask & LR_EMAIL) {
  449. _tcscpy( (LPTSTR) (RoutingInfo+sizeof(DWORD)), pDevInfo->ProfileName ? pDevInfo->ProfileName : TEXT("") );
  450. }
  451. if (!FaxSetRoutingInfo( FaxPortHandle, REGVAL_RM_EMAIL_GUID, RoutingInfo, cb )) {
  452. Error(("FaxSetRoutingInfo failed: %d\n", GetLastError()));
  453. }
  454. //
  455. // set the inbox profile name
  456. //
  457. *((LPDWORD)RoutingInfo) = (pDevInfo->Mask & LR_INBOX) > 0;
  458. if (pDevInfo->Mask & LR_INBOX) {
  459. _tcscpy( (LPTSTR) (RoutingInfo+sizeof(DWORD)), pDevInfo->ProfileName ? pDevInfo->ProfileName : TEXT("") );
  460. }
  461. if (!FaxSetRoutingInfo( FaxPortHandle, REGVAL_RM_INBOX_GUID, RoutingInfo, cb )) {
  462. Error(("FaxSetRoutingInfo failed: %d\n", GetLastError()));
  463. }
  464. MemFree( RoutingInfo );
  465. FaxClose( FaxPortHandle );
  466. }
  467. //
  468. // save the logging categories
  469. //
  470. if (!FaxSetLoggingCategories( gConfigData->hFaxSvc, gConfigData->pFaxLogging, gConfigData->NumberCategories )) {
  471. Error(("Cannot change fax logging category information: %d\n", GetLastError()));
  472. }
  473. ExitSaveFaxConfig:
  474. //
  475. // If an error was encountered, display a message box and return FALSE.
  476. // Otherwise, return TRUE to indicate success.
  477. //
  478. if (errorId != 0) {
  479. DisplayMessageDialog(hDlg, 0, 0, errorId);
  480. return FALSE;
  481. }
  482. if (gConfigData->priorityChanged) {
  483. DisplayMessageDialog(hDlg,
  484. MB_OK | MB_ICONINFORMATION,
  485. IDS_PRIORITY_CHANGE_TITLE,
  486. IDS_PRIORITY_CHANGE_MESSAGE);
  487. gConfigData->priorityChanged = FALSE;
  488. }
  489. return TRUE;
  490. }
  491. VOID
  492. FreeFaxDeviceAndConfigInfo(
  493. VOID
  494. )
  495. /*++
  496. Routine Description:
  497. Dispose of fax device and configuration information
  498. Arguments:
  499. NONE
  500. Return Value:
  501. NONE
  502. --*/
  503. {
  504. PCONFIG_PORT_INFO_2 pDevInfo = gConfigData->pDevInfo;
  505. while (gConfigData->cDevices > 0) {
  506. MemFree(pDevInfo->DeviceName);
  507. MemFree(pDevInfo->TSID);
  508. MemFree(pDevInfo->PrinterName);
  509. MemFree(pDevInfo->DirStore);
  510. MemFree(pDevInfo->ProfileName);
  511. MemFree(pDevInfo->CSID);
  512. gConfigData->cDevices--;
  513. pDevInfo++;
  514. }
  515. MemFree(gConfigData->pDevInfo);
  516. gConfigData->pDevInfo = NULL;
  517. gConfigData->cDevices = 0;
  518. FaxFreeBuffer(gConfigData->pFaxConfig);
  519. gConfigData->pFaxConfig = NULL;
  520. FaxFreeBuffer(gConfigData->pMapiProfiles);
  521. gConfigData->pMapiProfiles = NULL;
  522. }
  523. LPTSTR
  524. DuplicateString(
  525. LPCTSTR pSrcStr
  526. )
  527. /*++
  528. Routine Description:
  529. Make a duplicate of the specified character string
  530. Arguments:
  531. pSrcStr - Specifies the source string to be duplicated
  532. Return Value:
  533. Pointer to the duplicated string, NULL if there is an error
  534. --*/
  535. {
  536. LPTSTR pDestStr;
  537. INT size;
  538. if (pSrcStr == NULL)
  539. return NULL;
  540. size = SizeOfString(pSrcStr);
  541. if (pDestStr = MemAlloc(size))
  542. CopyMemory(pDestStr, pSrcStr, size);
  543. else
  544. Error(("Couldn't duplicate string: %ws\n", pSrcStr));
  545. return pDestStr;
  546. }
  547. VOID
  548. EnableControls(
  549. HWND hDlg,
  550. INT *pCtrlIds,
  551. BOOL enabled
  552. )
  553. /*++
  554. Routine Description:
  555. Enable or disable a set of controls in a dialog
  556. Arguments:
  557. hwnd - Specifies the handle to the dialog window
  558. pCtrlIds - Array of control IDs to be enabled or disabled (0 terminated)
  559. enabled - Whether to enable or disable the specified controls
  560. Return Value:
  561. NONE
  562. --*/
  563. {
  564. while (*pCtrlIds) {
  565. EnableWindow(GetDlgItem(hDlg, *pCtrlIds), enabled);
  566. pCtrlIds++;
  567. }
  568. }
  569. VOID
  570. ShowControls(
  571. HWND hDlg,
  572. INT *pCtrlIds,
  573. BOOL visible
  574. )
  575. /*++
  576. Routine Description:
  577. Show or hide a set of controls in a dialog
  578. Arguments:
  579. hwnd - Specifies the handle to the dialog window
  580. pCtrlIds - Array of control IDs to be shown or hidden (0 terminated)
  581. visible - Whether to show or hide the specified controls
  582. Return Value:
  583. NONE
  584. --*/
  585. {
  586. INT nCmdShow = visible ? SW_SHOW : SW_HIDE;
  587. while (*pCtrlIds) {
  588. ShowWindow(GetDlgItem(hDlg, *pCtrlIds), nCmdShow);
  589. pCtrlIds++;
  590. }
  591. }
  592. VOID
  593. LimitTextFields(
  594. HWND hDlg,
  595. INT *pLimitInfo
  596. )
  597. /*++
  598. Routine Description:
  599. Limit the maximum length for a number of text fields
  600. Arguments:
  601. hDlg - Specifies the handle to the dialog window
  602. pLimitInfo - Array of text field control IDs and their maximum length
  603. ID for the 1st text field, maximum length for the 1st text field
  604. ID for the 2nd text field, maximum length for the 2nd text field
  605. ...
  606. 0
  607. Note: The maximum length counts the NUL-terminator.
  608. Return Value:
  609. NONE
  610. --*/
  611. {
  612. while (*pLimitInfo != 0) {
  613. SendDlgItemMessage(hDlg, pLimitInfo[0], EM_SETLIMITTEXT, pLimitInfo[1]-1, 0);
  614. pLimitInfo += 2;
  615. }
  616. }
  617. INT
  618. DisplayMessageDialog(
  619. HWND hwndParent,
  620. UINT type,
  621. INT titleStrId,
  622. INT formatStrId,
  623. ...
  624. )
  625. /*++
  626. Routine Description:
  627. Display a message dialog box
  628. Arguments:
  629. hwndParent - Specifies a parent window for the error message dialog
  630. type - Specifies the type of message box to be displayed
  631. titleStrId - Title string (could be a string resource ID)
  632. formatStrId - Message format string (could be a string resource ID)
  633. ...
  634. Return Value:
  635. Same as the return value from MessageBox
  636. --*/
  637. {
  638. LPTSTR pTitle, pFormat, pMessage;
  639. INT result;
  640. va_list ap;
  641. pTitle = pFormat = pMessage = NULL;
  642. if ((pTitle = AllocStringZ(MAX_TITLE_LEN)) &&
  643. (pFormat = AllocStringZ(MAX_STRING_LEN)) &&
  644. (pMessage = AllocStringZ(MAX_MESSAGE_LEN)))
  645. {
  646. //
  647. // Load dialog box title string resource
  648. //
  649. if (titleStrId == 0)
  650. titleStrId = IDS_ERROR_DLGTITLE;
  651. LoadString(ghInstance, titleStrId, pTitle, MAX_TITLE_LEN);
  652. //
  653. // Load message format string resource
  654. //
  655. LoadString(ghInstance, formatStrId, pFormat, MAX_STRING_LEN);
  656. //
  657. // Compose the message string
  658. //
  659. va_start(ap, formatStrId);
  660. wvsprintf(pMessage, pFormat, ap);
  661. va_end(ap);
  662. //
  663. // Display the message box
  664. //
  665. if (type == 0)
  666. type = MB_OK | MB_ICONERROR;
  667. result = MessageBox(hwndParent, pMessage, pTitle, type);
  668. } else {
  669. MessageBeep(MB_ICONHAND);
  670. result = 0;
  671. }
  672. MemFree(pTitle);
  673. MemFree(pFormat);
  674. MemFree(pMessage);
  675. return result;
  676. }
  677. VOID
  678. ToggleListViewCheckbox(
  679. HWND hwndLV,
  680. INT index
  681. )
  682. /*++
  683. Routine Description:
  684. Toggle the checkbox associated with the specified list view item
  685. Arguments:
  686. hwndLV - Handle to the list view control
  687. index - Specifies the index of the interested item
  688. Return Value:
  689. NONE
  690. --*/
  691. {
  692. UINT state;
  693. if (IsListViewItemChecked(hwndLV, index))
  694. state = UNCHECKED_STATE;
  695. else
  696. state = CHECKED_STATE;
  697. ListView_SetItemState(hwndLV, index, state, LVIS_STATEIMAGEMASK);
  698. }
  699. VOID
  700. InitFaxDeviceListView(
  701. HWND hwndLV,
  702. DWORD flags,
  703. PCOLUMNINFO pColumnInfo
  704. )
  705. /*++
  706. Routine Description:
  707. Initialize the fax device list view
  708. Arguments:
  709. hwndLV - Handle to the fax device list view
  710. flags - Miscellaneous flag bits
  711. pColumnInfo - Specifies columns to be displayed and their relative widths
  712. ID for the 1st column, relative width for the 1st column
  713. ID for the 2nd column, relative width for the 2nd column
  714. ...
  715. 0, 0
  716. Return Value:
  717. NONE
  718. --*/
  719. {
  720. //
  721. // Column header string resource IDs
  722. //
  723. static INT columnHeaderIDs[MAX_COLUMNS] = {
  724. 0,
  725. IDS_DEVICE_NAME_COLUMN,
  726. IDS_CSID_COLUMN,
  727. IDS_TSID_COLUMN,
  728. IDS_STATUS_COLUMN,
  729. };
  730. INT index, nColumns, widthDenom, lvWidth;
  731. RECT rect;
  732. LV_COLUMN lvc;
  733. LV_ITEM lvi;
  734. TCHAR buffer[MAX_TITLE_LEN];
  735. //
  736. // Count the number of columns
  737. //
  738. if (hwndLV == NULL)
  739. return;
  740. nColumns = widthDenom = 0;
  741. while (pColumnInfo[nColumns].columnId) {
  742. widthDenom += pColumnInfo[nColumns].columnWidth;
  743. nColumns++;
  744. }
  745. Assert(nColumns > 0 && nColumns <= MAX_COLUMNS);
  746. Assert(pColumnInfo[0].columnId == COLUMN_DEVICE_NAME);
  747. lvc.mask = LVCF_TEXT;
  748. lvc.pszText = buffer;
  749. lvc.cchTextMax = MAX_TITLE_LEN;
  750. if (ListView_GetColumn(hwndLV, 0, &lvc) && ! IsEmptyString(buffer)) {
  751. //
  752. // The columns have already be inserted
  753. //
  754. ListView_DeleteAllItems(hwndLV);
  755. } else {
  756. //
  757. // This is the first time and the list view is not initialized
  758. // Insert the specified columns into the list view
  759. //
  760. GetClientRect(hwndLV, &rect);
  761. lvWidth = rect.right - rect.left;
  762. //
  763. // Insert a column of check boxes if requested
  764. //
  765. if (flags & LV_HASCHECKBOX) {
  766. HBITMAP hbmp;
  767. HIMAGELIST himl;
  768. if (hbmp = LoadBitmap(ghInstance, MAKEINTRESOURCE(IDB_CHECKSTATES))) {
  769. if (himl = ImageList_Create(16, 16, TRUE, 2, 0)) {
  770. ImageList_AddMasked(himl, hbmp, RGB(255, 0, 0));
  771. ListView_SetImageList(hwndLV, himl, LVSIL_STATE);
  772. } else
  773. Error(("LoadBitmap failed: %d\n", GetLastError()));
  774. DeleteObject(hbmp);
  775. } else
  776. Error(("LoadBitmap failed: %d\n", GetLastError()));
  777. }
  778. //
  779. // Insert list view columns
  780. //
  781. ZeroMemory(&lvc, sizeof(lvc));
  782. lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
  783. lvc.fmt = LVCFMT_LEFT;
  784. lvc.pszText = buffer;
  785. for (index=0; index < nColumns; index++) {
  786. lvc.cx = lvWidth * pColumnInfo[index].columnWidth / widthDenom;
  787. lvc.iSubItem = index;
  788. if (index == nColumns-1)
  789. lvc.cx -= GetSystemMetrics(SM_CXVSCROLL);
  790. LoadString(ghInstance,
  791. columnHeaderIDs[pColumnInfo[index].columnId],
  792. buffer,
  793. MAX_TITLE_LEN);
  794. if (ListView_InsertColumn(hwndLV, index, &lvc) == -1)
  795. Error(("ListView_InsertColumn failed\n"));
  796. }
  797. }
  798. //
  799. // Insert list view items list view content
  800. //
  801. ZeroMemory(&lvi, sizeof(lvi));
  802. lvi.iSubItem = 0;
  803. lvi.mask = LVIF_STATE | LVIF_TEXT;
  804. if (flags & LV_HASCHECKBOX) {
  805. lvi.state = UNCHECKED_STATE;
  806. lvi.stateMask = LVIS_STATEIMAGEMASK;
  807. }
  808. for (index = 0; index < gConfigData->cDevices; index ++) {
  809. //
  810. // The first column is always the device name
  811. //
  812. lvi.iItem = index;
  813. lvi.pszText = gConfigData->pDevInfo[index].DeviceName;
  814. if (ListView_InsertItem(hwndLV, &lvi) == -1) {
  815. Error(("ListView_InsertItem failed\n"));
  816. break;
  817. }
  818. }
  819. //
  820. // Display the remaining columns
  821. //
  822. UpdateFaxDeviceListViewColumns(hwndLV, pColumnInfo, 1);
  823. //
  824. // The initial selection is the first fax device in the list
  825. //
  826. ListView_SetItemState(hwndLV, 0, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED);
  827. }
  828. LPTSTR
  829. MakeDeviceStatusString(
  830. DWORD state
  831. )
  832. /*++
  833. Routine Description:
  834. Assemble fax device status string
  835. Arguments:
  836. state - Current state of the fax device
  837. Return Value:
  838. Pointer to the device status string, NULL if there is an error
  839. --*/
  840. {
  841. static struct _STATEBITINFO {
  842. DWORD bitFlag;
  843. INT stringId;
  844. } stateBitInfo[] = {
  845. FPS_AVAILABLE, IDS_STATUS_AVAILABLE,
  846. FPS_UNAVAILABLE, IDS_STATUS_UNAVAILABLE,
  847. FPS_SENDING, IDS_STATUS_SENDING,
  848. FPS_RECEIVING, IDS_STATUS_RECEIVING,
  849. FPS_ABORTING, IDS_STATUS_ABORTING,
  850. FPS_ROUTING, IDS_STATUS_ROUTING,
  851. FPS_DIALING, IDS_STATUS_DIALING,
  852. FPS_COMPLETED, IDS_STATUS_COMPLETED,
  853. FPS_HANDLED, IDS_STATUS_HANDLED,
  854. FPS_BUSY, IDS_STATUS_BUSY,
  855. FPS_NO_ANSWER, IDS_STATUS_NO_ANSWER,
  856. FPS_BAD_ADDRESS, IDS_STATUS_BAD_ADDRESS,
  857. FPS_NO_DIAL_TONE, IDS_STATUS_NO_DIAL_TONE,
  858. FPS_DISCONNECTED, IDS_STATUS_DISCONNECTED,
  859. FPS_FATAL_ERROR, IDS_STATUS_FATAL_ERROR,
  860. FPS_NOT_FAX_CALL, IDS_STATUS_NOT_FAX_CALL,
  861. FPS_CALL_DELAYED, IDS_STATUS_CALL_DELAYED,
  862. FPS_CALL_BLACKLISTED, IDS_STATUS_CALL_BLACKLISTED,
  863. FPS_INITIALIZING, IDS_STATUS_INITIALIZING,
  864. FPS_OFFLINE, IDS_STATUS_OFFLINE,
  865. FPS_ANSWERED, IDS_STATUS_ANSWERED
  866. };
  867. LPTSTR pBuffer, p;
  868. INT index, count, statusLen, separatorLen;
  869. BOOL appendSeparator = FALSE;
  870. TCHAR separator[MAX_TITLE_LEN];
  871. //
  872. // Load the string that's used separated status fields
  873. //
  874. if (! LoadString(ghInstance, IDS_STATUS_SEPARATOR, separator, MAX_TITLE_LEN))
  875. _tcscpy(separator, TEXT(", "));
  876. separatorLen = _tcslen(separator);
  877. //
  878. // Calculate how much space we need
  879. //
  880. count = sizeof(stateBitInfo) / sizeof(struct _STATEBITINFO);
  881. for (index=statusLen=0; index < count; index++) {
  882. if ((state & stateBitInfo[index].bitFlag) == stateBitInfo[index].bitFlag) {
  883. TCHAR buffer[MAX_TITLE_LEN];
  884. INT length;
  885. length = LoadString(ghInstance,
  886. stateBitInfo[index].stringId,
  887. buffer,
  888. MAX_TITLE_LEN);
  889. if (length == 0) {
  890. Error(("LoadString failed: %d\n", GetLastError()));
  891. return NULL;
  892. }
  893. statusLen += (length + separatorLen);
  894. }
  895. }
  896. //
  897. // Assemble the status string
  898. //
  899. if (p = pBuffer = MemAllocZ((statusLen + 1) * sizeof(TCHAR))) {
  900. for (index=0; index < count; index++) {
  901. if ((state & stateBitInfo[index].bitFlag) == stateBitInfo[index].bitFlag) {
  902. if (appendSeparator) {
  903. _tcscpy(p, separator);
  904. p += separatorLen;
  905. appendSeparator = FALSE;
  906. }
  907. statusLen = LoadString(ghInstance,
  908. stateBitInfo[index].stringId,
  909. p,
  910. MAX_TITLE_LEN);
  911. if (statusLen > 0) {
  912. p += statusLen;
  913. appendSeparator = TRUE;
  914. } else
  915. Error(("LoadString failed: %d\n", GetLastError()));
  916. }
  917. }
  918. }
  919. return pBuffer;
  920. }
  921. VOID
  922. UpdateFaxDeviceListViewColumns(
  923. HWND hwndLV,
  924. PCOLUMNINFO pColumnInfo,
  925. INT startColumn
  926. )
  927. /*++
  928. Routine Description:
  929. Refresh columns in the fax device list view
  930. Arguments:
  931. hwndLV - Handle to the fax device list view
  932. pColumnInfo - Specifies columns to be redisplayed
  933. startColumn - Specifies the first column index
  934. Return Value:
  935. NONE
  936. --*/
  937. {
  938. LPTSTR pBuffer, pColumnStr;
  939. LV_ITEM lvi;
  940. INT item, nItems, column, nColumns;
  941. //
  942. // Count the number of items in the list view
  943. //
  944. if ((hwndLV == NULL) ||
  945. (nItems = ListView_GetItemCount(hwndLV)) < 0 ||
  946. (nItems > gConfigData->cDevices))
  947. {
  948. return;
  949. }
  950. //
  951. // Count the total number of columns
  952. //
  953. for (nColumns=0; pColumnInfo[nColumns].columnId; nColumns++)
  954. NULL;
  955. ZeroMemory(&lvi, sizeof(lvi));
  956. lvi.mask = LVIF_TEXT;
  957. //
  958. // Go through each item in the list view
  959. //
  960. for (item=0; item < nItems; item++) {
  961. PCONFIG_PORT_INFO_2 pDevInfo = gConfigData->pDevInfo + item;
  962. lvi.iItem = item;
  963. //
  964. // Go through each column for every list view item
  965. //
  966. for (column=startColumn; column < nColumns; column++) {
  967. pBuffer = pColumnStr = NULL;
  968. switch (pColumnInfo[column].columnId) {
  969. case COLUMN_CSID:
  970. pColumnStr = pDevInfo->CSID;
  971. break;
  972. case COLUMN_TSID:
  973. pColumnStr = pDevInfo->TSID;
  974. break;
  975. case COLUMN_STATUS:
  976. pBuffer = pColumnStr = MakeDeviceStatusString(pDevInfo->State);
  977. break;
  978. default:
  979. Assert(FALSE);
  980. break;
  981. }
  982. lvi.iSubItem = column;
  983. lvi.pszText = pColumnStr ? pColumnStr : TEXT("");
  984. if (! ListView_SetItem(hwndLV, &lvi))
  985. Error(("ListView_SetItem failed\n"));
  986. MemFree(pBuffer);
  987. }
  988. }
  989. }
  990. INT
  991. BrowseCallbackProc(
  992. HWND hwnd,
  993. UINT uMsg,
  994. LPARAM lParam,
  995. LPARAM lpData
  996. )
  997. /*++
  998. Routine Description:
  999. Callback function for SHBrowseForFolder
  1000. Arguments:
  1001. hwnd - Handle to the browse dialog box
  1002. uMsg - Identifying the reason for the callback
  1003. lParam - Message parameter
  1004. lpData - Application-defined value given in BROWSEINFO.lParam
  1005. Return Value:
  1006. 0
  1007. --*/
  1008. {
  1009. if (uMsg == BFFM_INITIALIZED)
  1010. SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData);
  1011. return 0;
  1012. }
  1013. BOOL
  1014. DoBrowseForDirectory(
  1015. HWND hDlg,
  1016. INT textFieldId,
  1017. INT titleStrId
  1018. )
  1019. /*++
  1020. Routine Description:
  1021. Browse for a directory
  1022. Arguments:
  1023. hDlg - Specifies the dialog window on which the Browse button is displayed
  1024. textFieldId - Specifies the text field adjacent to the Browse button
  1025. titleStrId - Specifies the title to be displayed in the browse window
  1026. Return Value:
  1027. TRUE if successful, FALSE if the user presses Cancel
  1028. --*/
  1029. {
  1030. LPITEMIDLIST pidl;
  1031. TCHAR buffer[MAX_PATH];
  1032. TCHAR title[MAX_TITLE_LEN];
  1033. VOID SHFree(LPVOID);
  1034. BOOL result = FALSE;
  1035. BROWSEINFO bi = {
  1036. hDlg,
  1037. NULL,
  1038. buffer,
  1039. title,
  1040. BIF_RETURNONLYFSDIRS,
  1041. BrowseCallbackProc,
  1042. (LPARAM) buffer,
  1043. };
  1044. if (! LoadString(ghInstance, titleStrId, title, MAX_TITLE_LEN))
  1045. title[0] = NUL;
  1046. if (! GetDlgItemText(hDlg, textFieldId, buffer, MAX_PATH))
  1047. buffer[0] = NUL;
  1048. if (pidl = SHBrowseForFolder(&bi)) {
  1049. if (SHGetPathFromIDList(pidl, buffer)) {
  1050. if (_tcslen(buffer) > MAX_ARCHIVE_DIR)
  1051. DisplayMessageDialog(hDlg, 0, 0, IDS_DIR_TOO_LONG);
  1052. else {
  1053. MySetDlgItemText(hDlg, textFieldId, buffer);
  1054. result = TRUE;
  1055. }
  1056. }
  1057. SHFree(pidl);
  1058. }
  1059. return result;
  1060. }
  1061. BOOL
  1062. HandleHelpPopup(
  1063. HWND hDlg,
  1064. UINT message,
  1065. UINT wParam,
  1066. LPARAM lParam,
  1067. INT pageIndex
  1068. )
  1069. /*++
  1070. Routine Description:
  1071. Handle context-sensitive help in property sheet pages
  1072. Arguments:
  1073. hDlg, message, wParam, lParam - Parameters passed to the dialog procedure
  1074. pageIndex - Specifies the index of the current property sheet page
  1075. Return Value:
  1076. TRUE if the message is handle, FALSE otherwise
  1077. --*/
  1078. {
  1079. static LPDWORD arrayHelpIDs[MAX_PAGES] = {
  1080. clientOptionsHelpIDs,
  1081. personalCoverPageHelpIDs,
  1082. userInfoHelpIDs,
  1083. serverOptionsHelpIDs,
  1084. serverCoverPageHelpIDs,
  1085. sendOptionsHelpIDs,
  1086. receiveOptionsHelpIDs,
  1087. devicePriorityHelpIDs,
  1088. deviceStatusHelpIDs,
  1089. loggingHelpIDs,
  1090. NULL,
  1091. statusMonitorHelpIDs
  1092. };
  1093. Assert(pageIndex >= 0 && pageIndex < MAX_PAGES);
  1094. if (message == WM_HELP) {
  1095. WinHelp(((LPHELPINFO) lParam)->hItemHandle,
  1096. FAXCFG_HELP_FILENAME,
  1097. HELP_WM_HELP,
  1098. (DWORD) arrayHelpIDs[pageIndex]);
  1099. } else {
  1100. WinHelp((HWND) wParam,
  1101. FAXCFG_HELP_FILENAME,
  1102. HELP_CONTEXTMENU,
  1103. (DWORD) arrayHelpIDs[pageIndex]);
  1104. }
  1105. return TRUE;
  1106. }
  1107. PFAX_DEVICE_STATUS
  1108. FaxSvcGetDeviceStatus(
  1109. HANDLE hFaxSvc,
  1110. DWORD DeviceId
  1111. )
  1112. /*++
  1113. Routine Description:
  1114. Wrapper function for fax service API FaxGetDeviceStatus
  1115. Arguments:
  1116. hFaxSvc - Specifies a coneection handle to the fax service
  1117. DeviceId - Specifies the ID of the interested device
  1118. Return Value:
  1119. Pointer to a FAX_DEVICE_STATUS structure,
  1120. NULL if there is an error
  1121. --*/
  1122. {
  1123. PBYTE pFaxStatus = NULL;
  1124. HANDLE FaxPortHandle = NULL;
  1125. if ((hFaxSvc == NULL) ||
  1126. FaxOpenPort(hFaxSvc, DeviceId, PORT_OPEN_QUERY, &FaxPortHandle) == FALSE ||
  1127. !FaxGetDeviceStatus(FaxPortHandle, (PFAX_DEVICE_STATUS*)&pFaxStatus))
  1128. {
  1129. Error(("FaxGetDeviceStatus failed: %d\n", GetLastError()));
  1130. pFaxStatus = NULL;
  1131. }
  1132. if (FaxPortHandle) {
  1133. FaxClose( FaxPortHandle );
  1134. }
  1135. return (PFAX_DEVICE_STATUS) pFaxStatus;
  1136. }