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.

716 lines
15 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. faxcpl.c
  5. Abstract:
  6. Implementation of the control panel applet entry point
  7. Environment:
  8. Windows NT fax configuration applet
  9. Revision History:
  10. 02/27/96 -davidx-
  11. Created it.
  12. mm/dd/yy -author-
  13. description
  14. --*/
  15. #include "faxcpl.h"
  16. #include <tapi.h>
  17. #include "faxdev.h"
  18. //
  19. // Global variable definitions
  20. //
  21. HANDLE ghInstance = NULL; // Fax monitor DLL instance handle
  22. PCONFIGDATA gConfigData = NULL; // Fax configuration data structure
  23. INT _debugLevel = 1; // Control the amount of debug messages generated
  24. //
  25. // Setup API for determining whether the user has admin privilege on a machine
  26. //
  27. BOOL
  28. IsUserAdmin(
  29. VOID
  30. );
  31. extern BOOL WINAPI _CRT_INIT(HANDLE, ULONG, PVOID);
  32. BOOL
  33. DllEntryPoint(
  34. HANDLE hModule,
  35. ULONG ulReason,
  36. PCONTEXT pContext
  37. )
  38. /*++
  39. Routine Description:
  40. DLL initialization procedure.
  41. Arguments:
  42. hModule - DLL instance handle
  43. ulReason - Reason for the call
  44. pContext - Pointer to context (not used by us)
  45. Return Value:
  46. TRUE if DLL is initialized successfully, FALSE otherwise.
  47. --*/
  48. {
  49. switch (ulReason) {
  50. case DLL_PROCESS_ATTACH:
  51. #if DBG
  52. _CRT_INIT(hModule, ulReason, pContext);
  53. #endif
  54. ghInstance = hModule;
  55. break;
  56. case DLL_PROCESS_DETACH:
  57. FaxConfigCleanup();
  58. #if DBG
  59. _CRT_INIT(hModule, ulReason, pContext);
  60. #endif
  61. break;
  62. }
  63. return TRUE;
  64. }
  65. INT
  66. DetermineFaxConfigType(
  67. BOOL CplInit
  68. )
  69. /*++
  70. Routine Description:
  71. Determine the type of fax installation
  72. Arguments:
  73. CplInit - if this is TRUE then don't display the message box
  74. Return Value:
  75. FAXCONFIG_CLIENT - client installation
  76. FAXCONFIG_WORKSTATION - workstation installation
  77. FAXCONFIG_SERVER - server installation
  78. -1 if there is an error
  79. --*/
  80. {
  81. HANDLE FaxHandle = NULL;
  82. DWORD InstallType;
  83. DWORD InstalledPlatforms;
  84. DWORD ProductType;
  85. HKEY hKey;
  86. DWORD Size;
  87. DWORD Type;
  88. //
  89. // look at the machine registry for an install type
  90. // if the install type is for a network client, then
  91. // that is the cpl that we present. if there is a
  92. // network client and a server installed on this machine
  93. // then the install type will contain a mask of those
  94. // two values and this check will fail. this check
  95. // is here so that on a network client only install
  96. // we don't go off and try to talk to a server.
  97. //
  98. if (RegOpenKey( HKEY_LOCAL_MACHINE, REGKEY_FAX_SETUP, &hKey ) != ERROR_SUCCESS) {
  99. return -1;
  100. }
  101. Size = sizeof(InstallType);
  102. if (RegQueryValueEx( hKey, REGVAL_FAXINSTALL_TYPE, NULL, &Type, (LPBYTE) &InstallType, &Size ) != ERROR_SUCCESS) {
  103. RegCloseKey( hKey );
  104. return -1;
  105. }
  106. RegCloseKey( hKey );
  107. if (InstallType == FAX_INSTALL_NETWORK_CLIENT ) {
  108. return FAXCONFIG_CLIENT;
  109. }
  110. if (CplInit) {
  111. goto noconnect;
  112. }
  113. //
  114. // ask the server for the install type
  115. //
  116. if ((!FaxConnectFaxServer( gConfigData->pServerName, &FaxHandle)) ||
  117. (!FaxGetInstallType( FaxHandle, &InstallType, &InstalledPlatforms, &ProductType )))
  118. {
  119. if (FaxHandle) {
  120. FaxClose( FaxHandle );
  121. }
  122. DisplayMessageDialog( NULL, 0, 0, IDS_NULL_SERVICE_HANDLE );
  123. return -1;
  124. }
  125. FaxClose( FaxHandle );
  126. noconnect:
  127. Verbose(("Fax installation type: 0x%x\n", InstallType));
  128. if (InstallType & FAX_INSTALL_SERVER)
  129. InstallType = FAXCONFIG_SERVER;
  130. else if (InstallType & FAX_INSTALL_WORKSTATION)
  131. InstallType = FAXCONFIG_WORKSTATION;
  132. else
  133. InstallType = FAXCONFIG_CLIENT;
  134. return InstallType;
  135. }
  136. LPTSTR
  137. VerifyServerName(
  138. LPTSTR pServerName
  139. )
  140. /*++
  141. Routine Description:
  142. Verify the server name is well-formed
  143. Arguments:
  144. pServerName - Specifies the input server name
  145. Return Value:
  146. Pointer to a copy of the verified server name
  147. NULL if there is an error
  148. --*/
  149. {
  150. LPTSTR pVerifiedName;
  151. Assert(pServerName != NULL);
  152. if (pVerifiedName = MemAlloc(SizeOfString(pServerName) + 2*sizeof(TCHAR))) {
  153. //
  154. // Make sure the server name always starts with double backslash (\\)
  155. //
  156. pVerifiedName[0] = pVerifiedName[1] = TEXT(PATH_SEPARATOR);
  157. while (*pServerName == TEXT(PATH_SEPARATOR))
  158. pServerName++;
  159. _tcscpy(pVerifiedName+2, pServerName);
  160. }
  161. return pVerifiedName;
  162. }
  163. INT
  164. FaxConfigInit(
  165. LPTSTR pServerName,
  166. BOOL CplInit
  167. )
  168. /*++
  169. Routine Description:
  170. Initialize fax configuration DLL
  171. Arguments:
  172. pServerName - Specifies the name of the fax server machine.
  173. Pass NULL for local machine.
  174. CplInit - TRUE if called due to CPL_INIT message
  175. Return Value:
  176. -1 - An error has occurred
  177. FAXCONFIG_CLIENT -
  178. FAXCONFIG_SERVER -
  179. FAXCONFIG_WORKSTATION - Indicates the type of configuration the user can run
  180. --*/
  181. {
  182. //
  183. // Allocate memory for the fax configuration data structure
  184. //
  185. Assert(gConfigData == NULL);
  186. if (! (gConfigData = MemAllocZ(sizeof(CONFIGDATA)))) {
  187. Error(("Memory allocation failed\n"));
  188. return -1;
  189. }
  190. gConfigData->startSign = gConfigData->endSign = gConfigData;
  191. //
  192. // Make sure the server name is well-formed
  193. // Determine the type of fax configuration to be run
  194. //
  195. if ((pServerName && !(gConfigData->pServerName = VerifyServerName(pServerName))) ||
  196. (gConfigData->configType = DetermineFaxConfigType(CplInit)) < 0)
  197. {
  198. FaxConfigCleanup();
  199. return -1;
  200. }
  201. return gConfigData->configType;
  202. }
  203. VOID
  204. FaxConfigCleanup(
  205. VOID
  206. )
  207. /*++
  208. Routine Description:
  209. Deinitialize fax configuration DLL
  210. Arguments:
  211. NONE
  212. Return Value:
  213. NONE
  214. --*/
  215. {
  216. if (gConfigData != NULL) {
  217. Assert(ValidConfigData(gConfigData));
  218. //
  219. // Disconnect from the fax service if we're currently connected
  220. //
  221. if (gConfigData->hFaxSvc)
  222. FaxClose(gConfigData->hFaxSvc);
  223. //
  224. // Free up memory used to hold various information:
  225. // printer information
  226. // form information
  227. // port information
  228. //
  229. FreeFaxDeviceAndConfigInfo();
  230. FreeCoverPageInfo(gConfigData->pCPInfo);
  231. MemFree(gConfigData->pServerName);
  232. MemFree(gConfigData);
  233. gConfigData = NULL;
  234. DeinitTapiService();
  235. }
  236. }
  237. //
  238. // Information about each fax configuration page
  239. //
  240. typedef struct _FAXCFG_PAGEINFO {
  241. INT dialogId;
  242. DLGPROC dialogProc;
  243. } FAXCFG_PAGEINFO, *PFAXCFG_PAGEINFO;
  244. static FAXCFG_PAGEINFO ClientConfigPageInfo[] = {
  245. { IDD_CLIENT_COVERPG, ClientCoverPageProc },
  246. { IDD_USER_INFO, UserInfoProc }
  247. };
  248. static FAXCFG_PAGEINFO ServerConfigPageInfo[] = {
  249. { IDD_SERVER_OPTIONS, ServerOptionsProc },
  250. { IDD_SERVER_COVERPG, ServerCoverPageProc },
  251. { IDD_SEND_OPTIONS, SendOptionsProc },
  252. { IDD_RECEIVE_OPTIONS, ReceiveOptionsProc },
  253. { IDD_DEVICE_PRIORITY, DevicePriorityProc },
  254. { IDD_DEVICE_STATUS, DeviceStatusProc },
  255. { IDD_LOGGING, DiagLogProc },
  256. { IDD_SERVER_GENERAL, GeneralProc }
  257. };
  258. static FAXCFG_PAGEINFO WorkstationConfigPageInfo[] = {
  259. { IDD_CLIENT_COVERPG, ClientCoverPageProc },
  260. { IDD_USER_INFO, UserInfoProc },
  261. { IDD_SERVER_OPTIONS, ServerOptionsProc },
  262. { IDD_SEND_OPTIONS, SendOptionsProc },
  263. { IDD_RECEIVE_OPTIONS, ReceiveOptionsProc },
  264. { IDD_LOGGING, DiagLogProc },
  265. { IDD_STATUS_OPTIONS, StatusOptionsProc }
  266. };
  267. #define MAX_CLIENT_PAGES (sizeof(ClientConfigPageInfo) / sizeof(FAXCFG_PAGEINFO))
  268. #define MAX_SERVER_PAGES (sizeof(ServerConfigPageInfo) / sizeof(FAXCFG_PAGEINFO))
  269. #define MAX_WORKSTATION_PAGES (sizeof(WorkstationConfigPageInfo) / sizeof(FAXCFG_PAGEINFO))
  270. INT
  271. FaxConfigGetPageHandles(
  272. HPROPSHEETPAGE *phPropSheetPages,
  273. INT count,
  274. PFAXCFG_PAGEINFO pPageInfo,
  275. INT nPages
  276. )
  277. {
  278. //
  279. // Zero-initialize the input buffer
  280. //
  281. if (count > 0) {
  282. if (phPropSheetPages == NULL) {
  283. SetLastError(ERROR_INVALID_PARAMETER);
  284. return -1;
  285. }
  286. ZeroMemory(phPropSheetPages, sizeof(HPROPSHEETPAGE) * count);
  287. }
  288. //
  289. // Make sure the input buffer is large enough to hold all available pages
  290. //
  291. if (count >= nPages) {
  292. PROPSHEETPAGE psp;
  293. INT index;
  294. ZeroMemory(&psp, sizeof(psp));
  295. psp.dwSize = sizeof(PROPSHEETPAGE);
  296. psp.hInstance = ghInstance;
  297. psp.lParam = (LPARAM) gConfigData;
  298. for (index=0; index < nPages; index++) {
  299. //
  300. // Create property page handles
  301. //
  302. psp.pszTemplate = MAKEINTRESOURCE(pPageInfo[index].dialogId);
  303. psp.pfnDlgProc = pPageInfo[index].dialogProc;
  304. if (! (phPropSheetPages[index] = CreatePropertySheetPage(&psp))) {
  305. Error(("CreatePropertySheetPage failed: %d\n", GetLastError()));
  306. break;
  307. }
  308. }
  309. //
  310. // If we failed to create handles for all property pages,
  311. // we must destroy any handles we already created.
  312. //
  313. if (index < nPages) {
  314. while (--index >= 0)
  315. DestroyPropertySheetPage(phPropSheetPages[index]);
  316. return -1;
  317. }
  318. }
  319. return nPages;
  320. }
  321. BOOL
  322. DoConnectFaxService(
  323. VOID
  324. )
  325. /*++
  326. Routine Description:
  327. Connect to the fax service if necessary
  328. Arguments:
  329. NONE
  330. Return Value:
  331. TRUE if successful, FALSE otherwise
  332. --*/
  333. {
  334. DWORD InstallType;
  335. DWORD InstalledPlatforms;
  336. DWORD ProductType;
  337. Assert(ValidConfigData(gConfigData));
  338. Assert(gConfigData->configType == FAXCONFIG_SERVER ||
  339. gConfigData->configType == FAXCONFIG_WORKSTATION);
  340. if ((! gConfigData->hFaxSvc &&
  341. ! FaxConnectFaxServer(gConfigData->pServerName, &gConfigData->hFaxSvc)) ||
  342. ! FaxGetInstallType( gConfigData->hFaxSvc, &InstallType, &InstalledPlatforms, &ProductType ))
  343. {
  344. DisplayMessageDialog(NULL, 0, 0, IDS_NO_FAX_SERVICE);
  345. gConfigData->hFaxSvc = NULL;
  346. }
  347. return (gConfigData->hFaxSvc != NULL);
  348. }
  349. //
  350. // Get an array of handles to client/server/workstation configuration pages
  351. //
  352. // Parameters:
  353. //
  354. // phPropSheetPages - Specifies a buffer for storing property page handles
  355. // count - Specifies the maximum number of handles the input buffer can hold
  356. //
  357. // Return value:
  358. //
  359. // -1 - An error has occurred
  360. // >0 - Total number of configuration pages available
  361. //
  362. // Note:
  363. //
  364. // To figure out how large the input buffer should be, the caller can
  365. // first call these functions with phPropSheetPages set to NULL and
  366. // count set to 0.
  367. //
  368. INT
  369. FaxConfigGetClientPages(
  370. HPROPSHEETPAGE *phPropSheetPages,
  371. INT count
  372. )
  373. {
  374. //
  375. // We can only display client pages for non-workstation configuration types
  376. //
  377. if (!ValidConfigData(gConfigData) || gConfigData->configType == FAXCONFIG_WORKSTATION) {
  378. SetLastError(ERROR_INVALID_FUNCTION);
  379. return -1;
  380. }
  381. return FaxConfigGetPageHandles(phPropSheetPages,
  382. count,
  383. ClientConfigPageInfo,
  384. MAX_CLIENT_PAGES);
  385. }
  386. INT
  387. GetDeviceProviderPages(
  388. HPROPSHEETPAGE *phPropSheetPages,
  389. INT count
  390. )
  391. {
  392. HKEY hKey, hKeyDev;
  393. DWORD PageCnt = 0;
  394. DWORD Index = 0;
  395. WCHAR KeyName[MAX_PATH+1];
  396. WCHAR ImageName[MAX_PATH+1];
  397. HMODULE hMod;
  398. PFAXDEVCONFIGURE pFaxDevConfigure;
  399. DWORD Size;
  400. DWORD Type;
  401. if (RegOpenKey( HKEY_LOCAL_MACHINE, REGKEY_DEVICE_PROVIDER_KEY, &hKey ) != ERROR_SUCCESS) {
  402. return PageCnt;
  403. }
  404. while( RegEnumKey( hKey, Index, KeyName, sizeof(KeyName)/sizeof(WCHAR) ) == ERROR_SUCCESS) {
  405. if (RegOpenKey( hKey, KeyName, &hKeyDev ) == ERROR_SUCCESS) {
  406. Size = sizeof(KeyName);
  407. if (RegQueryValueEx( hKeyDev, REGVAL_IMAGE_NAME, 0, &Type, (LPBYTE)KeyName, &Size ) == ERROR_SUCCESS) {
  408. ExpandEnvironmentStrings( KeyName, ImageName, sizeof(ImageName)/sizeof(TCHAR) );
  409. hMod = LoadLibrary( ImageName );
  410. if (hMod) {
  411. pFaxDevConfigure = (PFAXDEVCONFIGURE) GetProcAddress( hMod, "FaxDevConfigure" );
  412. if (pFaxDevConfigure) {
  413. //
  414. // this device provider supports configuration
  415. // lets call the dll and get the pages
  416. //
  417. if (pFaxDevConfigure( &phPropSheetPages[PageCnt] )) {
  418. PageCnt += 1;
  419. }
  420. } else {
  421. FreeLibrary( hMod );
  422. }
  423. }
  424. }
  425. RegCloseKey( hKeyDev );
  426. }
  427. if (PageCnt == (DWORD) count) {
  428. break;
  429. }
  430. Index += 1;
  431. }
  432. RegCloseKey( hKey );
  433. return PageCnt;
  434. }
  435. INT
  436. FaxConfigGetServerPages(
  437. HPROPSHEETPAGE *phPropSheetPages,
  438. INT count
  439. )
  440. {
  441. DWORD DevPages = 0;
  442. DWORD SvrPages = 0;
  443. //
  444. // We can only display server pages for server configuration type
  445. //
  446. if (!ValidConfigData(gConfigData) || gConfigData->configType != FAXCONFIG_SERVER) {
  447. SetLastError(ERROR_INVALID_FUNCTION);
  448. return -1;
  449. }
  450. if (!DoConnectFaxService()) {
  451. return -1;
  452. }
  453. SvrPages = FaxConfigGetPageHandles(
  454. phPropSheetPages,
  455. count,
  456. ServerConfigPageInfo,
  457. MAX_SERVER_PAGES
  458. );
  459. if (SvrPages) {
  460. count -= SvrPages;
  461. phPropSheetPages += SvrPages;
  462. }
  463. DevPages = GetDeviceProviderPages( phPropSheetPages, count );
  464. if (DevPages) {
  465. count -= DevPages;
  466. phPropSheetPages += DevPages;
  467. }
  468. return SvrPages + DevPages;
  469. }
  470. INT
  471. FaxConfigGetWorkstationPages(
  472. HPROPSHEETPAGE *phPropSheetPages,
  473. INT count
  474. )
  475. {
  476. DWORD DevPages = 0;
  477. DWORD WksPages = 0;
  478. //
  479. // We can only display workstation pages for workstation configuration type
  480. //
  481. if (!ValidConfigData(gConfigData) || gConfigData->configType != FAXCONFIG_WORKSTATION) {
  482. SetLastError(ERROR_INVALID_FUNCTION);
  483. return -1;
  484. }
  485. if (! DoConnectFaxService())
  486. return -1;
  487. WksPages = FaxConfigGetPageHandles(
  488. phPropSheetPages,
  489. count,
  490. WorkstationConfigPageInfo,
  491. MAX_WORKSTATION_PAGES
  492. );
  493. if (WksPages) {
  494. count -= WksPages;
  495. phPropSheetPages += WksPages;
  496. }
  497. DevPages = GetDeviceProviderPages( phPropSheetPages, count );
  498. if (DevPages) {
  499. count -= DevPages;
  500. phPropSheetPages += DevPages;
  501. }
  502. return WksPages + DevPages;
  503. }