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.

2072 lines
59 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // File: util.cpp
  4. //
  5. // Module: CMDIAL32.DLL
  6. //
  7. // Synopsis: Various utility functions
  8. //
  9. // Copyright (c) 1996-1999 Microsoft Corporation
  10. //
  11. // Author: dondu Created 01/01/96
  12. //
  13. //+----------------------------------------------------------------------------
  14. #include "cmmaster.h"
  15. #include "DynamicLib.h"
  16. #include "profile_str.h"
  17. #include "tunl_str.h"
  18. #include "stp_str.h"
  19. #include "dun_str.h"
  20. #include "linkdll.cpp" // LinkToDll and BindLinkage
  21. //
  22. // Get the common functions AddAllKeysInCurrentSectionToCombo
  23. // and GetPrivateProfileStringWithAlloc
  24. //
  25. #include "gppswithalloc.cpp"
  26. const TCHAR* const c_pszTunnelName = TEXT(" Tunnel");
  27. const TCHAR* const c_pszRegCurrentVersion = TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion");
  28. const TCHAR* const c_pszRegCsdVersion = TEXT("CSDVersion");
  29. const TCHAR* const c_pszIconMgrClass = TEXT("IConnMgr Class");
  30. const TCHAR* const c_pszCmEntryPasswordHandling = TEXT("PasswordHandling");
  31. //+----------------------------------------------------------------------------
  32. //
  33. // Function: CmGetWindowTextAlloc
  34. //
  35. // Synopsis: Retrieves the text of a control in a dialog, returning the text in
  36. // a block of allocated memory
  37. //
  38. // Arguments: HWND hwndDlg - The window that owns the control
  39. // UINT nCtrl - The ID of the control
  40. //
  41. // Returns: LPTSTR - Ptr to buffer containing the window text
  42. //
  43. // History: nickball Created Header 4/1/98
  44. //
  45. //+----------------------------------------------------------------------------
  46. LPTSTR CmGetWindowTextAlloc(HWND hwndDlg, UINT nCtrl)
  47. {
  48. LPTSTR pszRes = NULL;
  49. HWND hwndCtrl = nCtrl ? GetDlgItem(hwndDlg, nCtrl) : hwndDlg;
  50. if (hwndCtrl)
  51. {
  52. size_t nLen = GetWindowTextLengthU(hwndCtrl);
  53. pszRes = (LPTSTR)CmMalloc((nLen+2)*sizeof(TCHAR));
  54. if (pszRes)
  55. {
  56. GetWindowTextU(hwndCtrl, pszRes, nLen+1);
  57. }
  58. }
  59. return (pszRes);
  60. }
  61. //+----------------------------------------------------------------------------
  62. //
  63. // Function: ReducePathToRelative
  64. //
  65. // Synopsis: Helper function, converts a full profile file path into a
  66. // relative path.
  67. //
  68. // Arguments: ArgsStruct *pArgs - Ptr to global Args struct
  69. // LPCTSTR pszFullPath - The full path to the file
  70. //
  71. //
  72. // Returns: LPTSTR - The relative path form or NULL
  73. //
  74. // Note: The file to be reduced should exist and be located
  75. // in the profile directory
  76. //
  77. // History: nickball Created 8/12/98
  78. //
  79. //+----------------------------------------------------------------------------
  80. LPTSTR ReducePathToRelative(ArgsStruct *pArgs, LPCTSTR pszFullPath)
  81. {
  82. MYDBGASSERT(pszFullPath);
  83. MYDBGASSERT(pArgs);
  84. if (NULL == pszFullPath || NULL == pArgs || FALSE == FileExists(pszFullPath))
  85. {
  86. return NULL;
  87. }
  88. //
  89. // Use CMS as base
  90. //
  91. LPTSTR pszReduced = CmStripPathAndExt(pArgs->piniService->GetFile());
  92. MYDBGASSERT(pszReduced);
  93. if (pszReduced)
  94. {
  95. //
  96. // Append the filename
  97. //
  98. pszReduced = CmStrCatAlloc(&pszReduced, TEXT("\\"));
  99. MYDBGASSERT(pszReduced);
  100. if (pszReduced)
  101. {
  102. LPTSTR pszFileName = StripPath(pszFullPath);
  103. MYDBGASSERT(pszFileName);
  104. if (pszFileName)
  105. {
  106. pszReduced = CmStrCatAlloc(&pszReduced, pszFileName);
  107. MYDBGASSERT(pszReduced);
  108. CmFree(pszFileName);
  109. if (pszReduced)
  110. {
  111. return pszReduced;
  112. }
  113. }
  114. }
  115. }
  116. CmFree(pszReduced);
  117. return NULL;
  118. }
  119. // get service name from the service file
  120. LPTSTR GetServiceName(CIni *piniService)
  121. {
  122. LPTSTR pszTmp;
  123. pszTmp = piniService->GPPS(c_pszCmSection,c_pszCmEntryServiceName);
  124. if (!*pszTmp)
  125. {
  126. //
  127. // failed to get service name, then use base filename
  128. //
  129. CmFree(pszTmp);
  130. pszTmp = CmStripPathAndExt(piniService->GetFile());
  131. //
  132. // Do not write the entry back to .CMS file - #4849
  133. //
  134. // piniService->WPPS(c_pszCmSection, c_pszCmEntryServiceName, pszTmp);
  135. }
  136. return (pszTmp);
  137. }
  138. //+----------------------------------------------------------------------------
  139. //
  140. // Function GetTunnelSuffix
  141. //
  142. // Synopsis Returns an allocated string containing the tunnel suffix
  143. //
  144. // Arguments None
  145. //
  146. // Returns LPTSTR - Ptr to the suffix in its entirety, caller must free
  147. //
  148. // History 06/14/99 nickball Created
  149. //
  150. //-----------------------------------------------------------------------------
  151. LPTSTR GetTunnelSuffix()
  152. {
  153. MYDBGASSERT(OS_W9X); // secondary connectoids only exist on 9X
  154. //
  155. // First copy the phrase " Tunnel", which is not localized
  156. //
  157. LPTSTR pszSuffix = CmStrCpyAlloc(c_pszTunnelName);
  158. //
  159. // Now retrieve the localizable phrase " (for advanced use only)"
  160. //
  161. if (pszSuffix)
  162. {
  163. LPTSTR pszTmp = CmLoadString(g_hInst, IDS_TUNNEL_SUFFIX);
  164. pszSuffix = CmStrCatAlloc(&pszSuffix, pszTmp);
  165. CmFree(pszTmp);
  166. }
  167. MYDBGASSERT(pszSuffix);
  168. return pszSuffix;
  169. }
  170. //+----------------------------------------------------------------------------
  171. //
  172. // Function GetDefaultDunSettingName
  173. //
  174. // Synopsis Get the default DUN name from the specified .CMS
  175. //
  176. // Arguments piniService - The service file object to be used.
  177. // fTunnel - Indicates if the profile is for tunneling
  178. //
  179. // Returns LPTSTR - Ptr to the DUN name
  180. //
  181. // History 10/28/98 nickball Created
  182. //
  183. //-----------------------------------------------------------------------------
  184. LPTSTR GetDefaultDunSettingName(CIni* piniService, BOOL fTunnelEntry)
  185. {
  186. //
  187. // Get the DUN name from the top level service file, ex: snowbird online service
  188. //
  189. LPTSTR pszTmp = NULL;
  190. if (fTunnelEntry)
  191. {
  192. pszTmp = piniService->GPPS(c_pszCmSection, c_pszCmEntryTunnelDun);
  193. MYDBGASSERT(pszTmp && *pszTmp); // CMAK writes this, it shouldn't be blank
  194. }
  195. else
  196. {
  197. pszTmp = piniService->GPPS(c_pszCmSection, c_pszCmEntryDun);
  198. }
  199. return (pszTmp);
  200. }
  201. //+----------------------------------------------------------------------------
  202. //
  203. // Function GetDunSettingName
  204. //
  205. // Synopsis Get the current DUN name
  206. //
  207. // Arguments pArgs - Ptr to ArgStruct
  208. // dwEntry - index of rasentry (ignored if fTunnel is true)
  209. // fTunnel - is this a VPN?
  210. //
  211. // Returns Dun setting name
  212. //
  213. // History 01-Nov-2000 SumitC Created
  214. //
  215. //-----------------------------------------------------------------------------
  216. LPTSTR GetDunSettingName(ArgsStruct * pArgs, DWORD dwEntry, BOOL fTunnel)
  217. {
  218. LPTSTR pszTmp = NULL;
  219. MYDBGASSERT(pArgs);
  220. MYDBGASSERT(fTunnel || (dwEntry <= 1));
  221. if (NULL == pArgs)
  222. {
  223. return NULL;
  224. }
  225. if (fTunnel)
  226. {
  227. pszTmp = pArgs->piniBothNonFav->GPPS(c_pszCmSection, c_pszCmEntryTunnelDun);
  228. MYDBGASSERT(pszTmp && *pszTmp); // CMAK writes this, it shouldn't be blank
  229. if (pszTmp && !*pszTmp)
  230. {
  231. // the "empty string" case
  232. CmFree(pszTmp);
  233. pszTmp = NULL;
  234. }
  235. }
  236. else
  237. {
  238. if (pArgs->aDialInfo[dwEntry].szDUN[0])
  239. {
  240. pszTmp = CmStrCpyAlloc(pArgs->aDialInfo[dwEntry].szDUN);
  241. }
  242. else
  243. {
  244. CIni * pIni = GetAppropriateIniService(pArgs, dwEntry);
  245. if (pIni)
  246. {
  247. pszTmp = pIni->GPPS(c_pszCmSection, c_pszCmEntryDun);
  248. delete pIni;
  249. }
  250. }
  251. }
  252. if (NULL == pszTmp)
  253. {
  254. pszTmp = GetDefaultDunSettingName(pArgs->piniService, fTunnel);
  255. }
  256. return pszTmp;
  257. }
  258. //+----------------------------------------------------------------------------
  259. //
  260. // Function GetCMSforPhoneBook
  261. //
  262. // Synopsis Get the name of the .CMS file that contains the current phonebook
  263. //
  264. // Arguments pArgs - Ptr to ArgStruct
  265. // dwEntry - index of rasentry
  266. //
  267. // Returns phonebook filename (NULL if error or not found)
  268. //
  269. // History 10-Nov-2000 SumitC Created
  270. //
  271. //-----------------------------------------------------------------------------
  272. LPTSTR GetCMSforPhoneBook(ArgsStruct * pArgs, DWORD dwEntry)
  273. {
  274. LPTSTR pszTmp = NULL;
  275. MYDBGASSERT(pArgs);
  276. MYDBGASSERT(dwEntry <= 1);
  277. if (NULL == pArgs)
  278. {
  279. return NULL;
  280. }
  281. PHONEINFO * pPhoneInfo = &(pArgs->aDialInfo[dwEntry]);
  282. if (pPhoneInfo && pPhoneInfo->szPhoneBookFile[0])
  283. {
  284. LPTSTR pszFileName = CmStrrchr(pPhoneInfo->szPhoneBookFile, TEXT('\\'));
  285. if (pszFileName)
  286. {
  287. pszTmp = CmStrCpyAlloc(CharNextU(pszFileName));
  288. }
  289. }
  290. return pszTmp;
  291. }
  292. //+----------------------------------------------------------------------------
  293. //
  294. // Function: FileExists
  295. //
  296. // Synopsis: Helper function to encapsulate determining if a file exists.
  297. //
  298. // Arguments: LPCTSTR pszFullNameAndPath - The FULL Name and Path of the file.
  299. //
  300. // Returns: BOOL - TRUE if the file is located
  301. //
  302. // History: nickball Created 3/9/98
  303. //
  304. //+----------------------------------------------------------------------------
  305. BOOL FileExists(LPCTSTR pszFullNameAndPath)
  306. {
  307. MYDBGASSERT(pszFullNameAndPath);
  308. if (pszFullNameAndPath && pszFullNameAndPath[0])
  309. {
  310. HANDLE hFile = CreateFileU(pszFullNameAndPath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
  311. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  312. if (hFile != INVALID_HANDLE_VALUE)
  313. {
  314. if (GetFileType(hFile) == FILE_TYPE_DISK)
  315. {
  316. CloseHandle(hFile);
  317. return TRUE;
  318. }
  319. else
  320. {
  321. CloseHandle(hFile);
  322. return FALSE;
  323. }
  324. }
  325. }
  326. return FALSE;
  327. }
  328. //+---------------------------------------------------------------------------
  329. //
  330. // Function: IsBlankString
  331. //
  332. // Synopsis: Check whether a given string contains only spaces(' ')
  333. //
  334. // Arguments: pszString string to be verified
  335. //
  336. // Returns: TRUE only space is in the string
  337. // FALSE otherwise
  338. //
  339. // History: byao Modified 4/11/97
  340. // byao Modified 4/14/97 Change the function to apply to
  341. // all strings (instead of phone no only).
  342. //----------------------------------------------------------------------------
  343. BOOL IsBlankString(LPCTSTR pszString)
  344. {
  345. MYDBGASSERT(pszString);
  346. DWORD dwIdx;
  347. DWORD dwLen = lstrlenU(pszString);
  348. if (NULL == pszString)
  349. {
  350. return FALSE;
  351. }
  352. for (dwIdx = 0; dwIdx < dwLen; dwIdx++)
  353. {
  354. if (pszString[dwIdx]!=TEXT(' '))
  355. {
  356. return FALSE;
  357. }
  358. }
  359. return TRUE;
  360. }
  361. //
  362. // Acceptable phone number characters
  363. //
  364. #define VALID_CTRL_CHARS TEXT("\03\026\030") // ctrl-c, ctrl-v, ctrl-x.
  365. #define VALID_PHONE_CHARS TEXT("0123456789AaBbCcDdPpTtWw!@$ -()+*#,\0")
  366. //+---------------------------------------------------------------------------
  367. //
  368. // Function: IsValidPhoneNumChar
  369. //
  370. // Synopsis: Helper function to encapsulate validation of a character to
  371. // determine if it is an acceptable input char for a phone number
  372. //
  373. // Arguments: TCHAR tChar - the char in question
  374. //
  375. // Returns: TRUE if valid
  376. // FALSE otherwise
  377. //
  378. // History: nickball - Created - 7/7/97
  379. //
  380. //----------------------------------------------------------------------------
  381. BOOL IsValidPhoneNumChar(TCHAR tChar)
  382. {
  383. LPTSTR lpValid = NULL;
  384. //
  385. // Scan thru the list of valid tapi characters
  386. //
  387. for (lpValid = VALID_PHONE_CHARS; *lpValid; lpValid++)
  388. {
  389. if (tChar == (TCHAR) *lpValid)
  390. {
  391. return TRUE;
  392. }
  393. }
  394. //
  395. // Scan thru the list of valid ctrl characters
  396. //
  397. for (lpValid = VALID_CTRL_CHARS; *lpValid; lpValid++)
  398. {
  399. if (tChar == (TCHAR) *lpValid)
  400. {
  401. return TRUE;
  402. }
  403. }
  404. return FALSE;
  405. }
  406. //+---------------------------------------------------------------------------
  407. //
  408. // Function: ReadMappingByRoot
  409. //
  410. // Synopsis: Read in the mapping from the [HKCU or HKLM] branch of the registry
  411. //
  412. // Arguments: hkRoot either HKCU or HKLM
  413. // pszDUN[IN] Connectoid name
  414. // pszMapping[IN] Full path of the service profile(.CMS) for this connectoid
  415. // dwNumCharsInMapping[IN] Number of chars in pszMapping, including the NULL char
  416. //
  417. // Returns: TRUE if registry key read in successfully
  418. // FALSE otherwise
  419. //
  420. //----------------------------------------------------------------------------
  421. BOOL ReadMappingByRoot(
  422. HKEY hkRoot,
  423. LPCTSTR pszDUN,
  424. LPTSTR pszMapping,
  425. DWORD dwNumCharsInMapping,
  426. BOOL bExpandEnvStrings
  427. )
  428. {
  429. MYDBGASSERT(pszDUN);
  430. MYDBGASSERT(pszMapping);
  431. MYDBGASSERT(dwNumCharsInMapping);
  432. if (NULL == pszDUN || NULL == pszMapping)
  433. {
  434. return FALSE;
  435. }
  436. TCHAR szTmp[MAX_PATH + 1] = TEXT("");
  437. DWORD dwNumBytesInTmp = sizeof(szTmp);
  438. DWORD dwRes;
  439. HKEY hkKey;
  440. DWORD dwType;
  441. dwRes = RegOpenKeyExU(hkRoot,
  442. c_pszRegCmMappings, // Mappings sub-key
  443. 0,
  444. KEY_READ,
  445. &hkKey);
  446. if (dwRes != ERROR_SUCCESS)
  447. {
  448. CMTRACE1(TEXT("ReadMappingByRoot() RegOpenKeyEx() failed, GLE=%u."), dwRes);
  449. return (FALSE);
  450. }
  451. dwRes = RegQueryValueExU(hkKey, pszDUN, NULL, &dwType, (LPBYTE) szTmp, &dwNumBytesInTmp);
  452. RegCloseKey(hkKey);
  453. //
  454. // If no value found, just bail
  455. //
  456. if ((dwRes != ERROR_SUCCESS) || (!*szTmp))
  457. {
  458. CMTRACE1(TEXT("ReadMappingByRoot() RegQueryValueEx() failed, GLE=%u."), dwRes);
  459. return FALSE;
  460. }
  461. //
  462. // Check for and expand environment strings
  463. //
  464. if (bExpandEnvStrings && (TEXT('%') == *szTmp))
  465. {
  466. CMTRACE1(TEXT("Expanding Mapping environment string as %s"), szTmp);
  467. dwRes = ExpandEnvironmentStringsU(szTmp, pszMapping, dwNumCharsInMapping);
  468. MYDBGASSERT(dwRes <= dwNumCharsInMapping);
  469. }
  470. else
  471. {
  472. lstrcpyU(pszMapping, szTmp);
  473. dwRes = lstrlenU(pszMapping) + 1;
  474. }
  475. #ifdef DEBUG
  476. if (dwRes <= dwNumCharsInMapping)
  477. {
  478. CMTRACE1(TEXT("ReadMappingByRoot() SUCCESS. Mapping is %s"), pszMapping);
  479. }
  480. else
  481. {
  482. CMTRACE(TEXT("ReadMappingByRoot() FAILED."));
  483. }
  484. #endif
  485. return (dwRes <= dwNumCharsInMapping);
  486. }
  487. //+---------------------------------------------------------------------------
  488. //
  489. // Function: ReadMapping
  490. //
  491. // Synopsis: Read in the mapping from the registry
  492. //
  493. // Arguments: pszDUN[IN] Connectoid name
  494. // pszMapping[IN] Full path of the service profile(.CMS) for this connectoid
  495. // dwMapping[IN] Number of chars in pszMapping, including the NULL char
  496. // fAllUser[IN] Look in the AllUser hive
  497. //
  498. // Returns: BOOL TRUE if found
  499. //
  500. //----------------------------------------------------------------------------
  501. BOOL ReadMapping(
  502. LPCTSTR pszDUN,
  503. LPTSTR pszMapping,
  504. DWORD dwMapping,
  505. BOOL fAllUser,
  506. BOOL bExpandEnvStrings)
  507. {
  508. BOOL fOk = FALSE;
  509. //
  510. // Copied from ntdef.h
  511. //
  512. #define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
  513. if (fAllUser)
  514. {
  515. CMTRACE1(TEXT("ReadMapping() - Reading AllUser Mapping for %s"), pszDUN);
  516. fOk = ReadMappingByRoot(HKEY_LOCAL_MACHINE, pszDUN, pszMapping, dwMapping, bExpandEnvStrings);
  517. }
  518. else
  519. {
  520. CMTRACE1(TEXT("ReadMapping() - Reading Single User Mapping for %s"), pszDUN);
  521. //
  522. // Only NT5 has single-user profiles
  523. //
  524. MYDBGASSERT(OS_NT5);
  525. if (OS_NT5)
  526. {
  527. //
  528. // There are cases where we aren't always running in the user context (certain
  529. // WinLogon cases and certain delete notification cases). At these times we
  530. // have impersonation setup but don't have direct access to the HKCU, thus
  531. // we use RtlOpenCurrentUser in these instances.
  532. //
  533. CDynamicLibrary libNtDll; // Destructor will call FreeLibrary
  534. HANDLE hCurrentUserKey = NULL;
  535. if (libNtDll.Load(TEXT("NTDLL.DLL")))
  536. {
  537. typedef NTSTATUS (NTAPI * RtlOpenCurrentUserPROC)(IN ULONG DesiredAccess,
  538. OUT PHANDLE CurrentUserKey);
  539. typedef NTSTATUS (NTAPI * NtClosePROC)(IN HANDLE Handle);
  540. RtlOpenCurrentUserPROC pfnRtlOpenCurrentUser;
  541. if ( (pfnRtlOpenCurrentUser = (RtlOpenCurrentUserPROC)libNtDll.GetProcAddress("RtlOpenCurrentUser")) != NULL)
  542. {
  543. if (NT_SUCCESS (pfnRtlOpenCurrentUser(KEY_READ | KEY_WRITE, &hCurrentUserKey)))
  544. {
  545. fOk = ReadMappingByRoot((HKEY)hCurrentUserKey, pszDUN, pszMapping, dwMapping, bExpandEnvStrings);
  546. NtClosePROC pfnNtClose;
  547. if ( (pfnNtClose = (NtClosePROC)libNtDll.GetProcAddress("NtClose")) != NULL)
  548. {
  549. pfnNtClose(hCurrentUserKey);
  550. }
  551. }
  552. }
  553. }
  554. MYDBGASSERT(hCurrentUserKey);
  555. }
  556. }
  557. return fOk;
  558. }
  559. //+----------------------------------------------------------------------------
  560. //
  561. // Function: StripPath
  562. //
  563. // Synopsis: Helper function to deal with the tedium of extracting the filename
  564. // part of a complete filename and path.
  565. //
  566. // Arguments: LPCTSTR pszFullNameAndPath - Ptr to the full filename with path
  567. //
  568. // Returns: LPTSTR - Ptr to an allocated buffer containing the dir, or NULL on failure.
  569. //
  570. // Note: It is up to the caller to provide reasonable input, the only requirement
  571. // is that the input contain '\'.
  572. //
  573. // History: nickball Created 3/31/98
  574. //
  575. //+----------------------------------------------------------------------------
  576. LPTSTR StripPath(LPCTSTR pszFullNameAndPath)
  577. {
  578. MYDBGASSERT(pszFullNameAndPath);
  579. if (NULL == pszFullNameAndPath)
  580. {
  581. return NULL;
  582. }
  583. //
  584. // Locate the last '\'
  585. //
  586. LPTSTR pszSlash = CmStrrchr(pszFullNameAndPath, TEXT('\\'));
  587. if (NULL == pszSlash)
  588. {
  589. MYDBGASSERT(FALSE);
  590. return NULL;
  591. }
  592. //
  593. // Return an allocated copy of the string beyond the last '\'
  594. //
  595. pszSlash = CharNextU(pszSlash);
  596. return (CmStrCpyAlloc(pszSlash));
  597. }
  598. //+----------------------------------------------------------------------------
  599. //
  600. // Function: NotifyUserOfExistingConnection
  601. //
  602. // Synopsis: Helper function to notify user that connection is either connect
  603. // ing or connected already.
  604. //
  605. // Arguments: HWND hwndParent - Hwnd of parent if any.
  606. // LPCM_CONNECTION pConnection - Ptr to CM_CONNECTION structure
  607. // containing state, entry name, etc.
  608. // BOOL fStatus - Flag indicating the status pane should be used for display.
  609. //
  610. // Returns: Nothing
  611. //
  612. // History: nickball Created Header 3/17/98
  613. //
  614. //+----------------------------------------------------------------------------
  615. void NotifyUserOfExistingConnection(HWND hwndParent, LPCM_CONNECTION pConnection, BOOL fStatus)
  616. {
  617. MYDBGASSERT(pConnection);
  618. //
  619. // Test assumptions
  620. //
  621. if (NULL == pConnection)
  622. {
  623. return;
  624. }
  625. MYDBGASSERT(CM_CONNECTED == pConnection->CmState ||
  626. CM_CONNECTING == pConnection->CmState ||
  627. CM_DISCONNECTING == pConnection->CmState);
  628. //
  629. // First load the correct message based upon state
  630. //
  631. int iMsgId;
  632. switch (pConnection->CmState)
  633. {
  634. case CM_CONNECTED:
  635. iMsgId = IDMSG_ALREADY_CONNECTED;
  636. break;
  637. case CM_CONNECTING:
  638. iMsgId = IDMSG_ALREADY_CONNECTING;
  639. break;
  640. case CM_DISCONNECTING:
  641. iMsgId = IDMSG_ALREADY_DISCONNECTING;
  642. break;
  643. default:
  644. MYDBGASSERT(FALSE);
  645. return;
  646. break;
  647. }
  648. //
  649. // Format the message with service name
  650. //
  651. LPTSTR pszMsg = CmFmtMsg(g_hInst, iMsgId, pConnection->szEntry);
  652. if (pszMsg)
  653. {
  654. //
  655. // Display according to requested output
  656. //
  657. if (fStatus)
  658. {
  659. AppendStatusPane(hwndParent, pszMsg);
  660. }
  661. else
  662. {
  663. MessageBoxEx(hwndParent, pszMsg, pConnection->szEntry, MB_OK|MB_ICONINFORMATION, LANG_USER_DEFAULT);
  664. }
  665. CmFree(pszMsg);
  666. }
  667. }
  668. //+----------------------------------------------------------------------------
  669. //
  670. // Function: GetConnection
  671. //
  672. // Synopsis: Helper routine to retrieve the connection data for the current
  673. // service from the connection table.
  674. //
  675. // Arguments: ArgsStruct *pArgs - Ptr to global Args struct
  676. //
  677. // Returns: Allocated ptr to a CM_CONNECTION or NULL
  678. //
  679. // History: nickball Created 2/23/98
  680. //
  681. //+----------------------------------------------------------------------------
  682. LPCM_CONNECTION GetConnection(ArgsStruct *pArgs)
  683. {
  684. MYDBGASSERT(pArgs);
  685. MYDBGASSERT(pArgs->pConnTable);
  686. LPCM_CONNECTION pConnection = (LPCM_CONNECTION) CmMalloc(sizeof(CM_CONNECTION));
  687. if (pArgs && pArgs->pConnTable && pConnection)
  688. {
  689. //
  690. // Retrieve the entry
  691. //
  692. if (FAILED(pArgs->pConnTable->GetEntry(pArgs->szServiceName, pConnection)))
  693. {
  694. CmFree(pConnection);
  695. pConnection = NULL;
  696. }
  697. }
  698. return pConnection;
  699. }
  700. //+----------------------------------------------------------------------------
  701. //
  702. // Function: SingleSpace
  703. //
  704. // Synopsis: Converts multiple space chars in a string to single spaces.
  705. // For example: "1 206 645 7865" becomes "1 206 645 7865"
  706. //
  707. // Arguments: LPTSTR pszStr - The string to be examined/modified
  708. //
  709. // Returns: Nothing
  710. //
  711. // Note: This is a fix for the MungePhone problem on W95 where TAPI adds
  712. // two spaces between the 9 and the 1 when dialing long distance
  713. // with a prefix. RAID #3198
  714. //
  715. // History: nickball 4/1/98 Created Header
  716. // nickball 4/1/98 Relocated from cm_misc.cpp
  717. //
  718. //+----------------------------------------------------------------------------
  719. void SingleSpace(LPTSTR pszStr)
  720. {
  721. LPTSTR pszTmp = pszStr;
  722. while (pszTmp && *pszTmp)
  723. {
  724. if (CmIsSpace(pszTmp) && CmIsSpace(pszTmp + 1))
  725. {
  726. lstrcpyU(pszTmp, (pszTmp + 1));
  727. }
  728. pszTmp++;
  729. }
  730. }
  731. //+----------------------------------------------------------------------------
  732. //
  733. // Function: Ip_GPPS
  734. //
  735. // Synopsis: Retrieves the result of a GPPS on the specified CIni object in R
  736. // ASIPADDR format. Used for reading IP addresses in INI files.
  737. //
  738. // Arguments: CIni *pIni - The Cini object to be used
  739. // LPCTSTR pszSection - String name of the section to be read
  740. // LPCTSTR pszEntry - String name of the entry to be read
  741. // RASIPADDR *pIP - Ptr to the RASIPADDR structure to be filled.
  742. //
  743. // Returns: static void - Nothing
  744. //
  745. // History: nickball Created Header 8/22/98
  746. //
  747. //+----------------------------------------------------------------------------
  748. void Ip_GPPS(CIni *pIni, LPCTSTR pszSection, LPCTSTR pszEntry, RASIPADDR *pIP)
  749. {
  750. LPTSTR pszTmp;
  751. LPTSTR pszOctet;
  752. RASIPADDR ip;
  753. MYDBGASSERT(pszSection);
  754. MYDBGASSERT(pszEntry);
  755. pszTmp = pIni->GPPS(pszSection, pszEntry);
  756. if (!*pszTmp)
  757. {
  758. CmFree(pszTmp);
  759. return;
  760. }
  761. memset(&ip,0,sizeof(ip));
  762. pszOctet = pszTmp;
  763. ip.a = (BYTE)CmAtol(pszOctet);
  764. while (CmIsDigit(pszOctet))
  765. {
  766. pszOctet++;
  767. }
  768. if (*pszOctet != '.')
  769. {
  770. CmFree(pszTmp);
  771. return;
  772. }
  773. pszOctet++;
  774. ip.b = (BYTE)CmAtol(pszOctet);
  775. while (CmIsDigit(pszOctet))
  776. {
  777. pszOctet++;
  778. }
  779. if (*pszOctet != '.')
  780. {
  781. CmFree(pszTmp);
  782. return;
  783. }
  784. pszOctet++;
  785. ip.c = (BYTE)CmAtol(pszOctet);
  786. while (CmIsDigit(pszOctet))
  787. {
  788. pszOctet++;
  789. }
  790. if (*pszOctet != '.')
  791. {
  792. CmFree(pszTmp);
  793. return;
  794. }
  795. pszOctet++;
  796. ip.d = (BYTE)CmAtol(pszOctet);
  797. while (CmIsDigit(pszOctet))
  798. {
  799. pszOctet++;
  800. }
  801. if (*pszOctet)
  802. {
  803. CmFree(pszTmp);
  804. return;
  805. }
  806. memcpy(pIP,&ip,sizeof(ip));
  807. CmFree(pszTmp);
  808. return;
  809. }
  810. //+----------------------------------------------------------------------------
  811. //
  812. // Function: CopyGPPS
  813. //
  814. // Synopsis: Copies the result of a GPPS call on the specified INI object to
  815. // the buffer specified in pszBuffer.
  816. //
  817. // Arguments: CIni *pIni - Ptr to the CIni object to be used.
  818. // LPCTSTR pszSection - String name the section to be read
  819. // LPCTSTR pszEntry - String name of the entry to be read
  820. // LPTSTR pszBuffer - The buffer to be filled with the result
  821. // size_t nLen - The size of the buffer to be filled
  822. //
  823. // Returns: static void - Nothing
  824. //
  825. // History: nickball Created Header 8/22/98
  826. //
  827. //+----------------------------------------------------------------------------
  828. void CopyGPPS(CIni *pIni, LPCTSTR pszSection, LPCTSTR pszEntry, LPTSTR pszBuffer, size_t nLen)
  829. {
  830. // REVIEW: Doesn't check input params
  831. LPTSTR pszTmp;
  832. pszTmp = pIni->GPPS(pszSection, pszEntry);
  833. if (*pszTmp)
  834. {
  835. lstrcpynU(pszBuffer, pszTmp, nLen);
  836. }
  837. CmFree(pszTmp);
  838. }
  839. //
  840. // From ras\ui\common\nouiutil\noui.c
  841. //
  842. CHAR HexChar(IN BYTE byte)
  843. /* Returns an ASCII hexidecimal character corresponding to 0 to 15 value,
  844. ** 'byte'.
  845. */
  846. {
  847. const CHAR* pszHexDigits = "0123456789ABCDEF";
  848. if (byte >= 0 && byte < 16)
  849. return pszHexDigits[ byte ];
  850. else
  851. return '0';
  852. }
  853. //
  854. // From ras\ui\common\nouiutil\noui.c
  855. //
  856. BYTE HexValue(IN CHAR ch)
  857. /* Returns the value 0 to 15 of hexadecimal character 'ch'.
  858. */
  859. {
  860. if (ch >= '0' && ch <= '9')
  861. return (BYTE )(ch - '0');
  862. else if (ch >= 'A' && ch <= 'F')
  863. return (BYTE )((ch - 'A') + 10);
  864. else if (ch >= 'a' && ch <= 'f')
  865. return (BYTE )((ch - 'a') + 10);
  866. else
  867. return 0;
  868. }
  869. //+----------------------------------------------------------------------------
  870. //
  871. // Function: StripCanonical
  872. //
  873. // Synopsis: Simple helper to strip canonical formatting codes from a phone number
  874. // Obviously the number is assumed to be in canonical format.
  875. //
  876. // Arguments: LPTSTR pszSrc - the string to be modifed
  877. //
  878. // Returns: Nothing
  879. //
  880. // History: nickball 09/16/98 Created
  881. //
  882. //+----------------------------------------------------------------------------
  883. void StripCanonical(LPTSTR pszSrc)
  884. {
  885. MYDBGASSERT(pszSrc);
  886. MYDBGASSERT(pszSrc);
  887. if (NULL == pszSrc || !*pszSrc)
  888. {
  889. return;
  890. }
  891. //
  892. // eg. +1 (425) 555 5555
  893. //
  894. LPTSTR pszNext = CharNextU(pszSrc);
  895. if (pszNext)
  896. {
  897. lstrcpyU(pszSrc, pszNext);
  898. //
  899. // eg. 1 (425) 555 5555
  900. //
  901. LPTSTR pszLast = CmStrchr(pszSrc, TEXT('('));
  902. if (pszLast)
  903. {
  904. pszNext = CharNextU(pszLast);
  905. if (pszNext)
  906. {
  907. lstrcpyU(pszLast, pszNext);
  908. //
  909. // eg. 1 425) 555 5555
  910. //
  911. pszLast = CmStrchr(pszSrc, TEXT(')'));
  912. if (pszLast)
  913. {
  914. pszNext = CharNextU(pszLast);
  915. if (pszNext)
  916. {
  917. lstrcpyU(pszLast, pszNext);
  918. }
  919. }
  920. //
  921. // eg. 1 425 555 5555
  922. //
  923. }
  924. }
  925. }
  926. }
  927. //+----------------------------------------------------------------------------
  928. //
  929. // Function: StripFirstElement
  930. //
  931. // Synopsis: Simple helper to strip the substring prior to the first space in
  932. // a string
  933. //
  934. // Arguments: LPTSTR pszSrc - the string to be modifed
  935. //
  936. // Returns: Nothing
  937. //
  938. // History: nickball 09/16/98 Created
  939. //
  940. //+----------------------------------------------------------------------------
  941. void StripFirstElement(LPTSTR pszSrc)
  942. {
  943. MYDBGASSERT(pszSrc);
  944. MYDBGASSERT(pszSrc);
  945. if (pszSrc && *pszSrc)
  946. {
  947. LPTSTR pszSpace = CmStrchr(pszSrc, TEXT(' '));
  948. if (pszSpace && *pszSpace)
  949. {
  950. LPTSTR pszTmp = CharNextU(pszSpace);
  951. if (pszTmp && *pszTmp)
  952. {
  953. lstrcpyU(pszSrc, pszTmp);
  954. }
  955. }
  956. }
  957. }
  958. //+----------------------------------------------------------------------------
  959. //
  960. // Function: FrontExistingUI
  961. //
  962. // Synopsis: Fronts existing UI for a given profile connect or settings attempt
  963. //
  964. // Arguments: CConnectionTable *pConnTable - ptr to connection table if any.
  965. // LPTSTR pszServiceName - the long service name
  966. // BOOL fConnect - flag indicating that the request is for connect
  967. //
  968. // Note: Caller is required to ensure that there is not an existing
  969. // (non-logon) window with the same service names as the title.
  970. //
  971. // Returns: TRUE if we fronted anything
  972. //
  973. //+----------------------------------------------------------------------------
  974. BOOL FrontExistingUI(CConnectionTable *pConnTable, LPCTSTR pszServiceName, BOOL fConnect)
  975. {
  976. LPTSTR pszPropTitle = GetPropertiesDlgTitle(pszServiceName);
  977. HWND hwndProperties = NULL;
  978. HWND hwndLogon = NULL;
  979. HWND hwndFront = NULL;
  980. BOOL bRet = FALSE;
  981. BOOL fLaunchProperties = FALSE;
  982. //
  983. // First look for a properties dialog
  984. //
  985. if (pszPropTitle)
  986. {
  987. hwndProperties = FindWindowExU(NULL, NULL, WC_DIALOG, pszPropTitle);
  988. }
  989. CmFree(pszPropTitle);
  990. //
  991. // Now see if we have a logon dialog up
  992. //
  993. hwndLogon = FindWindowExU(NULL, NULL, c_pszIconMgrClass, pszServiceName);
  994. //
  995. // Assume the common case, then consider the alternative scenarios.
  996. //
  997. hwndFront = hwndLogon ? hwndLogon : hwndProperties;
  998. //
  999. // Note: There is an ambiguous case in which both UIs are up, but aren't
  1000. // related, in which case we front according to the requested action.
  1001. //
  1002. if (hwndLogon && hwndProperties)
  1003. {
  1004. //
  1005. // We have both dialogs up, if the logon owns the properties dialog
  1006. // or the request is for a properties display, we'll front properties.
  1007. //
  1008. if (hwndLogon == GetParent(hwndProperties) || !fConnect)
  1009. {
  1010. hwndFront = hwndProperties;
  1011. }
  1012. }
  1013. //
  1014. // If we have a window handle, front it
  1015. //
  1016. if (hwndFront)
  1017. {
  1018. CMTRACE(TEXT("FrontExistingUI - Fronting existing connect instance UI"));
  1019. SetForegroundWindow(hwndFront);
  1020. bRet = TRUE;
  1021. //
  1022. // If the request is for properties, and there is a logon UI, but no
  1023. // properties, we want to launch the properties UI from the logon UI
  1024. // programmatically.
  1025. //
  1026. if (!fConnect && !hwndProperties) // fLaunchProperties)
  1027. {
  1028. if (pConnTable)
  1029. {
  1030. CM_CONNECTION Connection;
  1031. ZeroMemory(&Connection, sizeof(CM_CONNECTION));
  1032. //
  1033. // Don't launch in the middle of connecting, etc.
  1034. //
  1035. if (FAILED(pConnTable->GetEntry(pszServiceName, &Connection)))
  1036. {
  1037. PostMessageU(hwndLogon, WM_COMMAND, MAKEWPARAM(IDC_MAIN_PROPERTIES_BUTTON, 0), (LPARAM)0);
  1038. }
  1039. }
  1040. }
  1041. }
  1042. return bRet;
  1043. }
  1044. #if 0 // NT 301988
  1045. /*
  1046. //+----------------------------------------------------------------------------
  1047. //
  1048. // Function: IsAnotherInstanceRunning
  1049. //
  1050. // Synopsis: Check to see if another instance of the same profile running.
  1051. //
  1052. // Arguments: CConnectionTable *pConnTable - ptr to the connection table
  1053. // LPTSTR pszServiceName - the long service name
  1054. // DWORD dwFlags - the application flags FL_*
  1055. //
  1056. // Returns: Nothing
  1057. //
  1058. //+----------------------------------------------------------------------------
  1059. BOOL IsAnotherInstanceRunning(
  1060. CConnectionTable *pConnTable,
  1061. LPCTSTR pszServiceName,
  1062. DWORD dwFlags
  1063. )
  1064. {
  1065. BOOL fRet;
  1066. HWND hwnd;
  1067. LPTSTR pszPropTitle;
  1068. //
  1069. // first look for the Properties dialog
  1070. //
  1071. if (!(pszPropTitle = GetPropertiesDlgTitle(pszServiceName)))
  1072. {
  1073. return FALSE;
  1074. }
  1075. fRet = TRUE;
  1076. if (!(hwnd = FindWindowEx(NULL, NULL, WC_DIALOG, pszPropTitle)))
  1077. {
  1078. //
  1079. // now look for the main dialog. We make sure that the window returned
  1080. // is really the main dialog, not the Status dialog. Since the parent of
  1081. // the main dialog is the desktop, we can tell by making sure the parent
  1082. // of the window returned is the desktop window.
  1083. //
  1084. if ((hwnd = FindWindowEx(NULL, NULL, WC_DIALOG, pszServiceName)) &&
  1085. (GetWindow(hwnd, GW_OWNER) && GetWindow(hwnd, GW_OWNER) != GetDesktopWindow()))
  1086. {
  1087. hwnd = NULL;
  1088. }
  1089. }
  1090. CmFree(pszPropTitle);
  1091. BOOL fEntryExists;
  1092. CM_CONNECTION Connection;
  1093. ZeroMemory(&Connection, sizeof(CM_CONNECTION));
  1094. fEntryExists = pConnTable && SUCCEEDED(pConnTable->GetEntry(pszServiceName, &Connection));
  1095. if (hwnd)
  1096. {
  1097. CMTRACE(TEXT("Found a previous instance of the same profile."));
  1098. SetForegroundWindow(hwnd);
  1099. //
  1100. // if we're connecting, the "Properties" button is disabled and so we don't bring
  1101. // up the properties dialog. We don't want to do this also during disconnection
  1102. // and reconnecting.
  1103. //
  1104. if (dwFlags & FL_PROPERTIES &&
  1105. (!fEntryExists ||
  1106. fEntryExists &&
  1107. Connection.CmState != CM_CONNECTING &&
  1108. Connection.CmState != CM_RECONNECTPROMPT))
  1109. {
  1110. CMTRACE(TEXT("Bringing up the Properties dialog from the previous instance..."));
  1111. //
  1112. // try to bring up the properties dialog of the first instance
  1113. //
  1114. PostMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDC_MAIN_PROPERTIES_BUTTON, 0), (LPARAM)0);
  1115. }
  1116. }
  1117. else
  1118. {
  1119. //
  1120. // During disconnect and reconnect, we don't want to pop up either the main or the
  1121. // properties dlg. However, we want to let cmdial run if the Reconnect prompt is gone
  1122. // and the this is a reconnect request from CMMON
  1123. //
  1124. if (fEntryExists &&
  1125. (Connection.CmState == CM_DISCONNECTING ||
  1126. Connection.CmState == CM_RECONNECTPROMPT &&
  1127. dwFlags & FL_PROPERTIES))
  1128. {
  1129. fRet = TRUE;
  1130. }
  1131. else
  1132. {
  1133. fRet = FALSE;
  1134. }
  1135. }
  1136. return fRet;
  1137. }
  1138. */
  1139. #endif
  1140. LPTSTR GetPropertiesDlgTitle(
  1141. LPCTSTR pszServiceName
  1142. )
  1143. {
  1144. LPTSTR pszTmp = NULL;
  1145. LPTSTR pszTitle = NULL;
  1146. //
  1147. // first look for the Properties dialog
  1148. //
  1149. if (!(pszTmp = CmLoadString(g_hInst, IDS_PROPERTIES_SUFFIX)))
  1150. {
  1151. return NULL;
  1152. }
  1153. if (!(pszTitle = CmStrCpyAlloc(pszServiceName)))
  1154. {
  1155. CmFree(pszTmp);
  1156. return NULL;
  1157. }
  1158. if (!CmStrCatAlloc(&pszTitle, pszTmp))
  1159. {
  1160. CmFree(pszTmp);
  1161. CmFree(pszTitle);
  1162. return NULL;
  1163. }
  1164. CmFree(pszTmp);
  1165. return pszTitle;
  1166. }
  1167. //+----------------------------------------------------------------------------
  1168. //
  1169. // Function: GetPPTPMsgId
  1170. //
  1171. // Synopsis: Simple helper to determine appropriate PPTP msg based on OS cfg.
  1172. //
  1173. // Arguments: None
  1174. //
  1175. // Returns: Integer ID of resource string
  1176. //
  1177. // History: nickball 12/07/98 Created
  1178. //
  1179. //+----------------------------------------------------------------------------
  1180. int GetPPTPMsgId(void)
  1181. {
  1182. int nID;
  1183. if (OS_NT)
  1184. {
  1185. //
  1186. // We need to tell the user to re-apply the service pack after manual
  1187. // install of PPTP if they have one.
  1188. //
  1189. if (IsServicePackInstalled())
  1190. {
  1191. nID = IDMSG_NEED_PPTP_NT_SP;
  1192. }
  1193. else
  1194. {
  1195. nID = IDMSG_NEED_PPTP_NT; // NT w/o SP
  1196. }
  1197. }
  1198. else
  1199. {
  1200. nID = IDMSG_NEED_PPTP_WIN95;
  1201. }
  1202. return nID;
  1203. }
  1204. //+----------------------------------------------------------------------------
  1205. // Function IsServicePackInstalled
  1206. //
  1207. // Synopsis Checks the CSDVersion key in the registry to see if a service
  1208. // pack is installed on this machine
  1209. //
  1210. // Arguments None
  1211. //
  1212. // Returns TRUE if service pack (any SP) is installed
  1213. // FALSE if no service pack is installed
  1214. //
  1215. // History 2/4/98 VetriV Created
  1216. //-----------------------------------------------------------------------------
  1217. BOOL IsServicePackInstalled(void)
  1218. {
  1219. TCHAR szBuffer[MAX_PATH] = {TEXT("\0")};
  1220. HKEY hkey = NULL;
  1221. DWORD dwType = 0;
  1222. DWORD dwSize = sizeof(szBuffer);
  1223. if (ERROR_SUCCESS == RegOpenKeyExU(HKEY_LOCAL_MACHINE,
  1224. c_pszRegCurrentVersion,
  1225. 0,
  1226. KEY_READ,
  1227. &hkey))
  1228. {
  1229. if (ERROR_SUCCESS == RegQueryValueExU(hkey,
  1230. c_pszRegCsdVersion,
  1231. NULL,
  1232. &dwType,
  1233. (LPBYTE)szBuffer,
  1234. &dwSize))
  1235. {
  1236. if (szBuffer[0] != TEXT('\0'))
  1237. {
  1238. RegCloseKey(hkey);
  1239. return TRUE;
  1240. }
  1241. }
  1242. RegCloseKey(hkey);
  1243. }
  1244. return FALSE;
  1245. }
  1246. //+----------------------------------------------------------------------------
  1247. //
  1248. // Function: RegisterWindowClass
  1249. //
  1250. // Synopsis: Encapsulates registration of window class
  1251. //
  1252. // Arguments: HINSTANCE hInst - Hinst of DLL
  1253. //
  1254. // Returns: DWORD - GetLastError
  1255. //
  1256. // History: nickball Created Header 6/3/99
  1257. //
  1258. //+----------------------------------------------------------------------------
  1259. DWORD RegisterWindowClass(HINSTANCE hInst)
  1260. {
  1261. WNDCLASSEXA wc;
  1262. ZeroMemory(&wc, sizeof(wc));
  1263. if (GetClassInfoExA(NULL,(LPSTR)WC_DIALOG,&wc))
  1264. {
  1265. //
  1266. // Convert to Ansi before calling Ansi forms of APIs. We use the
  1267. // Ansi forms because GetClassInfoEx cannot be readily wrapped.
  1268. //
  1269. LPSTR pszClass = WzToSzWithAlloc(c_pszIconMgrClass);
  1270. if (!pszClass)
  1271. {
  1272. return ERROR_NOT_ENOUGH_MEMORY;
  1273. }
  1274. wc.lpszClassName = pszClass;
  1275. wc.cbSize = sizeof(wc);
  1276. wc.hInstance = hInst;
  1277. if (!RegisterClassExA(&wc))
  1278. {
  1279. DWORD dwError = GetLastError();
  1280. CMTRACE1(TEXT("RegisterWindowClass() RegisterClassEx() failed, GLE=%u."), dwError);
  1281. //
  1282. // Only fail if the class does not already exist
  1283. //
  1284. if (ERROR_CLASS_ALREADY_EXISTS != dwError)
  1285. {
  1286. CmFree(pszClass);
  1287. return dwError;
  1288. }
  1289. }
  1290. CmFree(pszClass);
  1291. }
  1292. return ERROR_SUCCESS;
  1293. }
  1294. //+----------------------------------------------------------------------------
  1295. //
  1296. // Function: UnRegisterWindowClass
  1297. //
  1298. // Synopsis: Encapsulates un-registering window class
  1299. //
  1300. // Arguments: HINSTANCE hInst - Hinst of DLL
  1301. //
  1302. // Returns: BOOL - result of UnregsiterClass
  1303. //
  1304. // History: nickball Created Header 6/3/99
  1305. //
  1306. //+----------------------------------------------------------------------------
  1307. BOOL UnRegisterWindowClass(HINSTANCE hInst)
  1308. {
  1309. return UnregisterClassU(c_pszIconMgrClass, g_hInst);
  1310. }
  1311. //+----------------------------------------------------------------------------
  1312. //
  1313. // Function: IsActionEnabled
  1314. //
  1315. // Synopsis: checks Registry to see if a command is allowed to run
  1316. //
  1317. // Arguments: CONST WCHAR *pszProgram - Name of program to be executed
  1318. // CONST WCHAR *pszServiceName - Long service name
  1319. // CONST WCHAR *pszServiceFileName - Full path to Service file
  1320. // LPDWORD lpdwLoadType - Ptr to be filled with load type
  1321. //
  1322. // Returns: TRUE if action is allowed @ this time
  1323. //
  1324. // Notes: Checks SOFTWARE\Microsoft\Connection Manager\<ServiceName>
  1325. // Under which you will have the Values for each command
  1326. // 0 - system32 directory
  1327. // 1 - profile directory
  1328. //
  1329. // History: v-vijayb Created Header 07/20/99
  1330. // nickball Revised 07/27/99
  1331. //
  1332. //+----------------------------------------------------------------------------
  1333. BOOL IsActionEnabled(CONST WCHAR *pszProgram,
  1334. CONST WCHAR *pszServiceName,
  1335. CONST WCHAR *pszServiceFileName,
  1336. LPDWORD lpdwLoadType)
  1337. {
  1338. HKEY hKey;
  1339. DWORD dwLoadFlags, cb;
  1340. BOOL fIsAllowed = FALSE;
  1341. WCHAR szSubKey[MAX_PATH + 1];
  1342. WCHAR szBaseName[MAX_PATH + 1];
  1343. WCHAR szPath[MAX_PATH + 1];
  1344. WCHAR *pszTmp;
  1345. MYDBGASSERT(pszProgram && pszServiceName && pszServiceFileName && lpdwLoadType);
  1346. if (NULL == pszProgram ||
  1347. NULL == pszServiceName ||
  1348. NULL == pszServiceFileName ||
  1349. NULL == lpdwLoadType)
  1350. {
  1351. return FALSE;
  1352. }
  1353. *lpdwLoadType = -1;
  1354. if (!IsLogonAsSystem())
  1355. {
  1356. return (TRUE);
  1357. }
  1358. MYDBGASSERT(OS_NT);
  1359. lstrcpyW(szPath, pszProgram);
  1360. //
  1361. // Check for extension. We don't allow anything that doesn't have an extension.
  1362. //
  1363. pszTmp = CmStrrchrW(szPath, TEXT('.'));
  1364. if (pszTmp == NULL)
  1365. {
  1366. return (FALSE);
  1367. }
  1368. //
  1369. // Get Basename
  1370. //
  1371. pszTmp = CmStrrchrW(szPath, TEXT('\\'));
  1372. if (pszTmp)
  1373. {
  1374. lstrcpyW(szBaseName, CharNextW(pszTmp));
  1375. *pszTmp = TEXT('\0');
  1376. }
  1377. else
  1378. {
  1379. lstrcpyW(szBaseName, pszProgram);
  1380. }
  1381. lstrcpyW(szSubKey, L"SOFTWARE\\Microsoft\\Connection Manager\\");
  1382. lstrcatW(szSubKey, pszServiceName);
  1383. lstrcatW(szSubKey, L"\\WinLogon Actions");
  1384. if (ERROR_SUCCESS == RegOpenKeyExW(HKEY_LOCAL_MACHINE, szSubKey, 0, KEY_READ, &hKey) )
  1385. {
  1386. cb = sizeof(dwLoadFlags);
  1387. if (ERROR_SUCCESS == RegQueryValueExW(hKey, szBaseName, NULL, NULL, (PBYTE) &dwLoadFlags, &cb))
  1388. {
  1389. switch (dwLoadFlags)
  1390. {
  1391. case 0: // system32 directory only
  1392. //
  1393. // No paths in this case, .CMS entry should match key name
  1394. //
  1395. if (0 == lstrcmpiW(szBaseName, szPath))
  1396. {
  1397. fIsAllowed = TRUE;
  1398. *lpdwLoadType = dwLoadFlags;
  1399. }
  1400. break;
  1401. case 1: // profile directory only
  1402. //
  1403. // Get servicename path
  1404. //
  1405. pszTmp = CmStripFileNameW(pszServiceFileName, FALSE);
  1406. if (pszTmp && 0 == lstrcmpiW(pszTmp, szPath))
  1407. {
  1408. fIsAllowed = TRUE;
  1409. *lpdwLoadType = dwLoadFlags;
  1410. }
  1411. CmFree(pszTmp);
  1412. break;
  1413. default: // invalid flag
  1414. CMTRACE1(TEXT("IsActionEnabled() - Invalid LoadFlags %d"), dwLoadFlags);
  1415. goto OnError;
  1416. break;
  1417. }
  1418. }
  1419. OnError:
  1420. RegCloseKey(hKey);
  1421. }
  1422. if (fIsAllowed == FALSE)
  1423. {
  1424. CMTRACE1W(L"IsActionEnabled(returned FALSE) %s", pszProgram);
  1425. }
  1426. return (fIsAllowed);
  1427. }
  1428. //+----------------------------------------------------------------------------
  1429. //
  1430. // Function: ApplyPasswordHandlingToBuffer
  1431. //
  1432. // Synopsis: Convert password: all upper case, all lower case, or no conversion
  1433. //
  1434. // Arguments: ArgsStruct *pArgs - Ptr to global Args struct
  1435. // LPTSTR pszBuffer - Buffer to be modified
  1436. //
  1437. // Returns: Nothing
  1438. //
  1439. // Note: Available types are: PWHANDLE_LOWER, PWHANDLE_UPPER, PWHANDLE_NONE:
  1440. //
  1441. // History: nickball Created 03/03/00
  1442. //
  1443. //+----------------------------------------------------------------------------
  1444. void ApplyPasswordHandlingToBuffer(ArgsStruct *pArgs,
  1445. LPTSTR pszBuffer)
  1446. {
  1447. MYDBGASSERT(pArgs);
  1448. MYDBGASSERT(pszBuffer);
  1449. if (NULL == pArgs || NULL == pszBuffer)
  1450. {
  1451. return;
  1452. }
  1453. CIni *piniService = GetAppropriateIniService(pArgs, pArgs->nDialIdx);
  1454. if (piniService)
  1455. {
  1456. switch (piniService->GPPI(c_pszCmSection, c_pszCmEntryPasswordHandling))
  1457. {
  1458. case PWHANDLE_LOWER:
  1459. CharLowerU(pszBuffer);
  1460. break;
  1461. case PWHANDLE_UPPER:
  1462. CharUpperU(pszBuffer);
  1463. break;
  1464. case PWHANDLE_NONE:
  1465. default:
  1466. break;
  1467. }
  1468. }
  1469. delete piniService;
  1470. }
  1471. //+----------------------------------------------------------------------------
  1472. //
  1473. // Function: ApplyDomainHandlingToDialParams
  1474. //
  1475. // Synopsis: Handles the messy details of Domain management relative to username
  1476. // Returns a buffer containing the original buffer and (if appropriate)
  1477. // the domain prepended.
  1478. //
  1479. // Arguments: ArgsStruct *pArgs - Ptr to global Args struct
  1480. // CIni *piniService - Ptr to the Cini object to be used
  1481. // LPTSTR pszBuffer - Ptr to the current buffer to which we'll prepend
  1482. //
  1483. // Returns: LPTSTR -
  1484. //
  1485. // History: nickball Created 03/04/00
  1486. //
  1487. //+----------------------------------------------------------------------------
  1488. LPTSTR ApplyDomainPrependToBufferAlloc(ArgsStruct *pArgs,
  1489. CIni *piniService,
  1490. LPTSTR pszBuffer,
  1491. LPCTSTR pszDunName)
  1492. {
  1493. MYDBGASSERT(pArgs);
  1494. MYDBGASSERT(piniService);
  1495. MYDBGASSERT(pszBuffer);
  1496. MYDBGASSERT(pszDunName);
  1497. if (NULL == pArgs || NULL == piniService || NULL == pszBuffer || NULL == pszDunName)
  1498. {
  1499. return NULL;
  1500. }
  1501. BOOL bPrependDomain = FALSE;
  1502. //
  1503. // Prepare the user name. We may need to pre-pend the domain
  1504. //
  1505. if (*pArgs->szDomain)
  1506. {
  1507. //
  1508. // There is a domain, see if pre-pending is explicitly set in the
  1509. // DUN setting for this connection.
  1510. //
  1511. LPTSTR pszDunEntry = NULL;
  1512. LPTSTR pszPreviousSection = NULL;
  1513. if (pszDunName && *pszDunName)
  1514. {
  1515. pszDunEntry = CmStrCpyAlloc(pszDunName);
  1516. }
  1517. else
  1518. {
  1519. pszDunEntry = GetDefaultDunSettingName(piniService, FALSE); // FALSE == fTunnelEntry, never called from DoTunnelDial
  1520. }
  1521. MYDBGASSERT(pszDunEntry);
  1522. if (pszDunEntry)
  1523. {
  1524. //
  1525. // Since we are going to call SetSection on piniService to set it up
  1526. // to retrieve the DUN setting name, we should save the existing value
  1527. // before we overwrite it.
  1528. //
  1529. pszPreviousSection = CmStrCpyAlloc(piniService->GetSection());
  1530. MYDBGASSERT(pszPreviousSection);
  1531. if (pszPreviousSection) // this will either be "" or the previous section name
  1532. {
  1533. LPTSTR pszSection = CmStrCpyAlloc(TEXT("&"));
  1534. pszSection = CmStrCatAlloc(&pszSection, pszDunEntry);
  1535. MYDBGASSERT(pszSection);
  1536. piniService->SetSection(pszSection);
  1537. CmFree(pszSection);
  1538. }
  1539. }
  1540. int nTmp = piniService->GPPI(c_pszCmSectionDunServer, c_pszCmEntryDunPrependDialupDomain, -1);
  1541. if (-1 == nTmp)
  1542. {
  1543. //
  1544. // There is no prepend flag, so on W9X infer from the VPN scenario.
  1545. // The inference is that if we're dialing a number that is part of
  1546. // a VPN scenario AND its a same-name logon, then we need to prepend
  1547. // the Domain to the user name (eg. REDMOND\username).
  1548. //
  1549. if (OS_W9X && pArgs->fUseTunneling && pArgs->fUseSameUserName)
  1550. {
  1551. bPrependDomain = TRUE;
  1552. }
  1553. }
  1554. else
  1555. {
  1556. bPrependDomain = (BOOL) nTmp;
  1557. }
  1558. //
  1559. // Restore the previous section to piniService to as not to have a function side effect.
  1560. //
  1561. if (pszPreviousSection)
  1562. {
  1563. piniService->SetSection(pszPreviousSection);
  1564. CmFree(pszPreviousSection);
  1565. }
  1566. CmFree(pszDunEntry);
  1567. }
  1568. //
  1569. // Build username as required
  1570. //
  1571. LPTSTR pszName = NULL;
  1572. if (bPrependDomain)
  1573. {
  1574. pszName = CmStrCpyAlloc(pArgs->szDomain);
  1575. CmStrCatAlloc(&pszName, TEXT("\\"));
  1576. CmStrCatAlloc(&pszName, pszBuffer);
  1577. }
  1578. else
  1579. {
  1580. pszName = CmStrCpyAlloc(pszBuffer);
  1581. }
  1582. return pszName;
  1583. }
  1584. //+----------------------------------------------------------------------------
  1585. //
  1586. // Function: GetPrefixAndSuffix
  1587. //
  1588. // Synopsis: Handles the messy details of determining the username prefix and
  1589. // suffix to be used. This data varies according to whether the
  1590. // referencING profile has either a prefix and suffix in which case
  1591. // they are used against all phone #s. However, if they do not exist
  1592. // in the referencING profile, then the prefix and suffix in the
  1593. // referecED profile (if any) are used.
  1594. //
  1595. // Arguments: ArgsStruct *pArgs - Ptr to global Args struct
  1596. // CIni *piniService - Ptr to the Cini object to be used
  1597. // LPTSTR *ppszUsernamePrefix - Address of pointer to be allocated
  1598. // filled w/ prefix.
  1599. // LPTSTR *ppszUsernamePrefix - Address of pointer to be allocated
  1600. // filled w/ suffix.
  1601. //
  1602. // Returns: Nothing, caller should validate output
  1603. //
  1604. // History: nickball Created 05/31/00
  1605. //
  1606. //+----------------------------------------------------------------------------
  1607. void GetPrefixSuffix(ArgsStruct *pArgs, CIni* piniService, LPTSTR *ppszUsernamePrefix, LPTSTR *ppszUsernameSuffix)
  1608. {
  1609. MYDBGASSERT(pArgs);
  1610. MYDBGASSERT(piniService);
  1611. MYDBGASSERT(ppszUsernameSuffix);
  1612. MYDBGASSERT(ppszUsernamePrefix);
  1613. if (NULL == pArgs || NULL == piniService || NULL == ppszUsernamePrefix || NULL == ppszUsernameSuffix)
  1614. {
  1615. return;
  1616. }
  1617. //
  1618. // If the referencING (top-level) service file includes a prefix or suffix,
  1619. // then we'll use it. Otherwise, we'll use the realm from the service file
  1620. // associated with the phone book from which the user selected the POP.
  1621. //
  1622. LPTSTR pszTmpPrefix = pArgs->piniService->GPPS(c_pszCmSection, c_pszCmEntryUserPrefix);
  1623. LPTSTR pszTmpSuffix = pArgs->piniService->GPPS(c_pszCmSection, c_pszCmEntryUserSuffix);
  1624. //
  1625. // Thus, if both prefix and suffix are empty and this is a referencED profile
  1626. // and the user has selected a phone # from a referenced pbk, we'll retrieve
  1627. // the data from the referencED service file.
  1628. //
  1629. if (pszTmpPrefix && pszTmpSuffix)
  1630. {
  1631. if (!*pszTmpPrefix && !*pszTmpSuffix)
  1632. {
  1633. if (pArgs->fHasRefs &&
  1634. lstrcmpiU(pArgs->aDialInfo[pArgs->nDialIdx].szPhoneBookFile, pArgs->piniService->GetFile()) != 0)
  1635. {
  1636. if (pszTmpPrefix)
  1637. {
  1638. CmFree(pszTmpPrefix);
  1639. }
  1640. if (pszTmpSuffix)
  1641. {
  1642. CmFree(pszTmpSuffix);
  1643. }
  1644. pszTmpPrefix = piniService->GPPS(c_pszCmSection, c_pszCmEntryUserPrefix);
  1645. pszTmpSuffix = piniService->GPPS(c_pszCmSection, c_pszCmEntryUserSuffix);
  1646. }
  1647. }
  1648. }
  1649. *ppszUsernamePrefix = pszTmpPrefix;
  1650. *ppszUsernameSuffix = pszTmpSuffix;
  1651. }
  1652. //+----------------------------------------------------------------------------
  1653. //
  1654. // Function: ApplyPrefixSuffixToBufferAlloc
  1655. //
  1656. // Synopsis: Handles the messy details of Domain management relative to username
  1657. // Updates the the RasDialParams as appropriate.
  1658. //
  1659. // Arguments: ArgsStruct *pArgs - Ptr to global Args struct
  1660. // CIni *piniService - Ptr to the Cini object to be used
  1661. // LPTSTR pszBuffer - Ptr to current buffer to which we'll apply
  1662. // suffix and prefix data.
  1663. //
  1664. // Returns: A new buffer allocation containing the original buffer
  1665. // with applied suffix and prefix data.
  1666. //
  1667. // Note: The CIni object is expected to be that associated with the current
  1668. // number. In other words, that returned by GetApporpriateIniService
  1669. //
  1670. // History: nickball Created 03/04/00
  1671. // nickball GetPrefixSuffix 05/31/00
  1672. //
  1673. //+----------------------------------------------------------------------------
  1674. LPTSTR ApplyPrefixSuffixToBufferAlloc(ArgsStruct *pArgs,
  1675. CIni *piniService,
  1676. LPTSTR pszBuffer)
  1677. {
  1678. MYDBGASSERT(pArgs);
  1679. MYDBGASSERT(piniService);
  1680. MYDBGASSERT(pszBuffer);
  1681. if (NULL == pArgs || NULL == piniService || NULL == pszBuffer)
  1682. {
  1683. return NULL;
  1684. }
  1685. LPTSTR pszUsernamePrefix = NULL;
  1686. LPTSTR pszUsernameSuffix = NULL;
  1687. GetPrefixSuffix(pArgs, piniService, &pszUsernamePrefix, &pszUsernameSuffix);
  1688. //
  1689. // Don't double prepend the prefix if there is one. User may have
  1690. // provided a fully qualified name including realm prefix.
  1691. // (eg. MSN/user)
  1692. //
  1693. if (*pszUsernamePrefix)
  1694. {
  1695. DWORD dwBufferLen = lstrlenU(pszBuffer);
  1696. DWORD dwPrefixLen = lstrlenU(pszUsernamePrefix);
  1697. if (dwBufferLen > dwPrefixLen)
  1698. {
  1699. TCHAR cReplacedChar = pszBuffer[dwPrefixLen];
  1700. pszBuffer[dwPrefixLen] = TEXT('\0');
  1701. if (0 == lstrcmpiU(pszBuffer, pszUsernamePrefix))
  1702. {
  1703. //
  1704. // The prefix has already been prepended. Let's clear out
  1705. // the pszUsernamePrefix field.
  1706. //
  1707. *pszUsernamePrefix = TEXT('\0');
  1708. }
  1709. pszBuffer[dwPrefixLen] = cReplacedChar;
  1710. }
  1711. }
  1712. CmStrCatAlloc(&pszUsernamePrefix, pszBuffer);
  1713. //
  1714. // Don't double append the suffix if there is one. User may have
  1715. // provided a fully qualified name including domain suffix.
  1716. // (eg. [email protected])
  1717. //
  1718. if (*pszUsernameSuffix)
  1719. {
  1720. DWORD dwSuffixLen = lstrlenU(pszUsernameSuffix);
  1721. DWORD dwUserNameLen = lstrlenU(pszUsernamePrefix);
  1722. //
  1723. // Make sure the total username is longer than the suffix itself,
  1724. // otherwise we have no change of a double append. If it is longer than
  1725. // the suffix length, go ahead and make sure we aren't appending the suffix
  1726. // twice.
  1727. //
  1728. if (dwSuffixLen && (dwSuffixLen < dwUserNameLen))
  1729. {
  1730. if (0 == lstrcmpiU(&(pszUsernamePrefix[dwUserNameLen - dwSuffixLen]), pszUsernameSuffix))
  1731. {
  1732. *pszUsernameSuffix = TEXT('\0');
  1733. }
  1734. }
  1735. }
  1736. CmStrCatAlloc(&pszUsernamePrefix, pszUsernameSuffix);
  1737. CmFree(pszUsernameSuffix);
  1738. //
  1739. // pszUsernamePrefix now contains the final product
  1740. //
  1741. return pszUsernamePrefix;
  1742. }
  1743. //+----------------------------------------------------------------------------
  1744. //
  1745. // Function: InBetween
  1746. //
  1747. // Synopsis: Simple function which returns TRUE if the passed in number is
  1748. // in between the given lower and upper bounds. Note that the
  1749. // boundaries themselves are considered in bounds.
  1750. //
  1751. // Arguments: int iLowerBound - lower bound
  1752. // int iNumber - number to test
  1753. // int iUpperBound - upper bound
  1754. //
  1755. // Returns: TRUE if the number is equal to either of the boundaries or in between
  1756. // the two numbers. Note that if the lower and upper boundary numbers
  1757. // are backwards it will always return FALSE.
  1758. //
  1759. //
  1760. // History: quintinb Created 07/24/00
  1761. //
  1762. //+----------------------------------------------------------------------------
  1763. BOOL InBetween(int iLowerBound, int iNumber, int iUpperBound)
  1764. {
  1765. return ((iLowerBound <= iNumber) && (iUpperBound >= iNumber));
  1766. }