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.

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