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.

735 lines
22 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1998.
  5. //
  6. // File: D U N I M P O R T . C P P
  7. //
  8. // Contents: Functions that handles .DUN files for RAS connections
  9. // created in win9x
  10. //
  11. // Notes:
  12. //
  13. // Author: TongL 15 March 1999
  14. //
  15. //----------------------------------------------------------------------------
  16. #include "pch.h"
  17. #pragma hdrstop
  18. #include "dunimport.h"
  19. #include "raserror.h"
  20. #include "ncras.h"
  21. #include "connutil.h"
  22. #define RAS_MaxEntryName 256
  23. #define MAXLONGLEN 11 // Maximum long string length
  24. #define MAXIPADDRLEN 20
  25. #define SIZE_ReadBuf 0x00008000 // 32K buffer size
  26. #define NUM_IP_FIELDS 4
  27. #define MIN_IP_VALUE 0
  28. #define MAX_IP_VALUE 255
  29. #define CH_DOT L'.'
  30. const WCHAR c_szPhoneBookPath[] = L"\\Microsoft\\Network\\Connections\\Pbk\\rasphone.pbk";
  31. const WCHAR c_szRASDT[] = L"RASDT_";
  32. const WCHAR c_szEntrySection[] = L"Entry";
  33. const WCHAR c_szEntryName[] = L"Entry_Name";
  34. const WCHAR c_szML[] = L"Multilink";
  35. const WCHAR c_szPhoneSection[] = L"Phone";
  36. const WCHAR c_szDialAsIs[] = L"Dial_As_Is";
  37. const WCHAR c_szPhoneNumber[] = L"Phone_Number";
  38. const WCHAR c_szAreaCode[] = L"Area_Code";
  39. const WCHAR c_szCountryCode[] = L"Country_Code";
  40. const WCHAR c_szCountryID[] = L"Country_ID";
  41. const WCHAR c_szYes[] = L"yes";
  42. const WCHAR c_szNo[] = L"no";
  43. const WCHAR c_szDeviceSection[] = L"Device";
  44. const WCHAR c_szDeviceType[] = L"Type";
  45. const WCHAR c_szModem[] = L"modem";
  46. const WCHAR c_szVpn[] = L"vpn";
  47. const WCHAR c_szDeviceName[] = L"Name";
  48. const WCHAR c_szServerSection[] = L"Server";
  49. const WCHAR c_szServerType[] = L"Type";
  50. const WCHAR c_szPPP[] = L"PPP";
  51. const WCHAR c_szSLIP[] = L"SLIP";
  52. const WCHAR c_szRAS[] = L"RAS";
  53. const WCHAR c_szSWCompress[] = L"SW_Compress";
  54. const WCHAR c_szPWEncrypt[] = L"PW_Encrypt";
  55. const WCHAR c_szNetLogon[] = L"Network_Logon";
  56. const WCHAR c_szSWEncrypt[] = L"SW_Encrypt";
  57. const WCHAR c_szNetBEUI[] = L"Negotiate_NetBEUI";
  58. const WCHAR c_szIPX[] = L"Negotiate_IPX/SPX";
  59. const WCHAR c_szIP[] = L"Negotiate_TCP/IP";
  60. const WCHAR c_szIPSection[] = L"TCP/IP";
  61. const WCHAR c_szIPSpec[] = L"Specify_IP_Address";
  62. const WCHAR c_szIPAddress[] = L"IP_address";
  63. const WCHAR c_szServerSpec[] = L"Specify_Server_Address";
  64. const WCHAR c_szDNSAddress[] = L"DNS_address";
  65. const WCHAR c_szDNSAltAddress[] = L"DNS_Alt_address";
  66. const WCHAR c_szWINSAddress[] = L"WINS_address";
  67. const WCHAR c_szWINSAltAddress[]= L"WINS_Alt_address";
  68. const WCHAR c_szIPCompress[] = L"IP_Header_Compress";
  69. const WCHAR c_szRemoteGateway[] = L"Gateway_On_Remote";
  70. //+---------------------------------------------------------------------------
  71. //
  72. // Function: HrInvokeDunFile_Internal
  73. //
  74. // Purpose: This is the entry point for DUN file invoking
  75. //
  76. // Arguments:
  77. // szFileName [in] The .DUN file name
  78. //
  79. // Returns: S_OK if succeeded, failure code otherwise
  80. //
  81. HRESULT HrInvokeDunFile_Internal(IN LPWSTR szDunFile)
  82. {
  83. HRESULT hr = S_OK;
  84. WCHAR szEntryName[RAS_MaxEntryName+1];
  85. tstring strPhoneBook;
  86. hr = HrGetPhoneBookFile(strPhoneBook);
  87. if (SUCCEEDED(hr))
  88. {
  89. // Get the size of device configuration
  90. // This also validates an exported file
  91. //
  92. hr = HrGetEntryName(szDunFile, szEntryName, strPhoneBook);
  93. if ((HRESULT_FROM_WIN32(ERROR_CANNOT_OPEN_PHONEBOOK) == hr) ||
  94. (HRESULT_FROM_WIN32(ERROR_CANNOT_FIND_PHONEBOOK_ENTRY) == hr))
  95. {
  96. // create a new entry in the current user's phonebook
  97. hr = HrImportPhoneBookInfo(szDunFile, szEntryName, strPhoneBook);
  98. }
  99. if (SUCCEEDED(hr))
  100. {
  101. // get the GUID of this connection
  102. RASENTRY* pRasEntry = NULL;
  103. hr = HrRasGetEntryProperties( strPhoneBook.c_str(),
  104. szEntryName,
  105. &pRasEntry,
  106. NULL);
  107. if(SUCCEEDED(hr))
  108. {
  109. // dial the connection
  110. hr = HrLaunchConnection(pRasEntry->guidId);
  111. MemFree(pRasEntry);
  112. }
  113. }
  114. }
  115. TraceError("HrInvokeDunFile_Internal", hr);
  116. return hr;
  117. }
  118. //+---------------------------------------------------------------------------
  119. //
  120. // Function: HrGetPhoneBookFile
  121. //
  122. // Purpose: This function will return the proper path to the current user's
  123. // phonebook.
  124. //
  125. // Arguments:
  126. // szFileName [in] The .DUN file name
  127. //
  128. // Returns: S_OK if succeeded, failure code otherwise
  129. //
  130. HRESULT HrGetPhoneBookFile(tstring& strPhoneBook)
  131. {
  132. HRESULT hr = S_OK;
  133. strPhoneBook = c_szEmpty;
  134. LPITEMIDLIST pidl;
  135. LPMALLOC pMalloc;
  136. WCHAR szDir[MAX_PATH+1];
  137. hr = SHGetSpecialFolderLocation(NULL,
  138. CSIDL_APPDATA,
  139. &pidl);
  140. if(SUCCEEDED(hr))
  141. {
  142. if (SHGetPathFromIDList(pidl, szDir))
  143. {
  144. strPhoneBook = szDir;
  145. TraceTag(ttidDun, "The path to the application directory is: %S", strPhoneBook.c_str());
  146. // release the memory by using the the shell's IMalloc ptr
  147. //
  148. if (SUCCEEDED(SHGetMalloc(&pMalloc)))
  149. {
  150. pMalloc->Free(pidl);
  151. }
  152. }
  153. else
  154. {
  155. hr = E_FAIL;
  156. }
  157. }
  158. if (SUCCEEDED(hr))
  159. {
  160. TraceTag(ttidDun, "The path to the phonebook is: %S", strPhoneBook.c_str());
  161. strPhoneBook += c_szPhoneBookPath;
  162. }
  163. return hr;
  164. }
  165. //+---------------------------------------------------------------------------
  166. //
  167. // Function: HrGetEntryName
  168. //
  169. // Purpose: This function validates and returns the entry name
  170. //
  171. // Arguments:
  172. // szDunFile [in] The .dun file created on win9x
  173. // szEntryName [in] The entry name for this connection
  174. //
  175. // Returns: S_OK if valid and is a new entry
  176. // S_FALSE if valid and but is an existing entry
  177. // otherwise, specific error
  178. //
  179. HRESULT HrGetEntryName(IN LPWSTR szFileName,
  180. IN LPWSTR szEntryName,
  181. tstring & strPhoneBook)
  182. {
  183. HRESULT hr = S_OK;
  184. DWORD dwRet;
  185. // Get the entry name
  186. //
  187. dwRet = GetPrivateProfileString(c_szEntrySection,
  188. c_szEntryName,
  189. c_szEmpty,
  190. szEntryName,
  191. RAS_MaxEntryName+1,
  192. szFileName);
  193. // no entry name
  194. if (dwRet <= 0)
  195. {
  196. return HRESULT_FROM_WIN32(ERROR_CORRUPT_PHONEBOOK);
  197. }
  198. // Check if entry name already exists in phonebook
  199. //
  200. RASENTRY* pRasEntry = NULL;
  201. hr = HrRasGetEntryProperties( strPhoneBook.c_str(),
  202. szEntryName,
  203. &pRasEntry,
  204. NULL);
  205. MemFree(pRasEntry);
  206. TraceErrorOptional("HrGetEntryName", hr,
  207. ((HRESULT_FROM_WIN32(ERROR_CANNOT_OPEN_PHONEBOOK) == hr) ||
  208. (HRESULT_FROM_WIN32(ERROR_CANNOT_FIND_PHONEBOOK_ENTRY) == hr)));
  209. return hr;
  210. }
  211. //+---------------------------------------------------------------------------
  212. //
  213. // Function: HrImportPhoneBookInfo
  214. //
  215. // Purpose: This function checks if the RAS entry already exists in the
  216. // current user's phonebook
  217. //
  218. // Arguments:
  219. // szEntryName [in] The entry name for this connection
  220. //
  221. // Returns: TRUE if already exists, FALSE otherwise
  222. //
  223. HRESULT HrImportPhoneBookInfo( IN LPWSTR szDunFile,
  224. IN LPWSTR szEntryName,
  225. tstring & strPhoneBook)
  226. {
  227. HRESULT hr = S_OK;
  228. RASENTRY RasEntry = {0};
  229. // Get the phone number
  230. //
  231. hr = HrImportPhoneInfo(&RasEntry, szDunFile);
  232. if (SUCCEEDED(hr))
  233. {
  234. // Get device name, type and config
  235. //
  236. ImportDeviceInfo(&RasEntry, szDunFile);
  237. // Get Server Type settings
  238. //
  239. ImportServerInfo(&RasEntry, szDunFile);
  240. // Get IP address
  241. //
  242. ImportIPInfo(&RasEntry, szDunFile);
  243. // Prompt for user name and password
  244. RasEntry.dwfOptions |= RASEO_PreviewUserPw;
  245. // Save it to the phonebook
  246. //
  247. DWORD dwRet;
  248. RasEntry.dwSize = sizeof(RASENTRY);
  249. RasEntry.dwType = RASET_Phone;
  250. dwRet = RasSetEntryProperties(strPhoneBook.c_str(),
  251. szEntryName,
  252. &RasEntry,
  253. sizeof(RASENTRY),
  254. NULL,
  255. 0);
  256. hr = HRESULT_FROM_WIN32(dwRet);
  257. TraceError("RasSetEntryProperties", hr);
  258. }
  259. TraceError("HrImportPhoneBookInfo", hr);
  260. return hr;
  261. }
  262. //+---------------------------------------------------------------------------
  263. //
  264. // Function: HrImportPhoneInfo
  265. //
  266. // Purpose: This function imports the phone number
  267. //
  268. // Arguments:
  269. // szFileName [in] The .DUN file name
  270. //
  271. // Returns:
  272. //
  273. HRESULT HrImportPhoneInfo(RASENTRY * pRasEntry,
  274. IN LPWSTR szFileName)
  275. {
  276. HRESULT hr = S_OK;
  277. // szLocalPhoneNumber
  278. if (GetPrivateProfileString(c_szPhoneSection,
  279. c_szPhoneNumber,
  280. c_szEmpty,
  281. pRasEntry->szLocalPhoneNumber,
  282. celems(pRasEntry->szLocalPhoneNumber),
  283. szFileName) == 0)
  284. {
  285. hr = HRESULT_FROM_WIN32(ERROR_CORRUPT_PHONEBOOK);
  286. };
  287. if (SUCCEEDED(hr))
  288. {
  289. WCHAR szYesNo[MAXLONGLEN+1];
  290. GetPrivateProfileString(c_szPhoneSection,
  291. c_szDialAsIs,
  292. c_szYes,
  293. szYesNo,
  294. celems(szYesNo),
  295. szFileName);
  296. // Do we have to get country code and area code?
  297. //
  298. if (!lstrcmpiW(szYesNo, c_szNo))
  299. {
  300. // use country and area codes
  301. pRasEntry->dwfOptions |= RASEO_UseCountryAndAreaCodes;
  302. // If we cannot get the country ID or it is zero, default to dial as is
  303. //
  304. if ((pRasEntry->dwCountryID = GetPrivateProfileInt( c_szPhoneSection,
  305. c_szCountryID,
  306. 0,
  307. szFileName)) != 0)
  308. {
  309. pRasEntry->dwCountryCode = GetPrivateProfileInt(c_szPhoneSection,
  310. c_szCountryCode,
  311. 1,
  312. szFileName);
  313. }
  314. GetPrivateProfileString(c_szPhoneSection,
  315. c_szAreaCode,
  316. c_szEmpty,
  317. pRasEntry->szAreaCode,
  318. celems(pRasEntry->szAreaCode),
  319. szFileName);
  320. };
  321. }
  322. TraceError("HrImportPhoneInfo", hr);
  323. return hr;
  324. }
  325. //+---------------------------------------------------------------------------
  326. //
  327. // Function: ImportDeviceInfo
  328. //
  329. // Purpose: This function imports the device info
  330. //
  331. // Arguments:
  332. // szFileName [in] The .DUN file name
  333. //
  334. // Returns:
  335. //
  336. VOID ImportDeviceInfo(RASENTRY * pRasEntry,
  337. IN LPWSTR szFileName)
  338. {
  339. WCHAR szDeviceType[RAS_MaxDeviceType+1];
  340. // Get the device type
  341. //
  342. if (GetPrivateProfileString(c_szDeviceSection,
  343. c_szDeviceType,
  344. c_szEmpty,
  345. szDeviceType,
  346. celems(szDeviceType),
  347. szFileName))
  348. {
  349. if (!lstrcmpiW(szDeviceType, c_szModem))
  350. {
  351. lstrcpyW(pRasEntry->szDeviceType, RASDT_Modem);
  352. }
  353. else if (!lstrcmpiW(szDeviceType, c_szVpn))
  354. {
  355. lstrcpyW(pRasEntry->szDeviceType, RASDT_Vpn);
  356. }
  357. else
  358. {
  359. AssertSz(FALSE, "Unknown device type");
  360. }
  361. // Get the device name
  362. //
  363. GetPrivateProfileString( c_szDeviceSection,
  364. c_szDeviceName,
  365. c_szEmpty,
  366. pRasEntry->szDeviceName,
  367. celems(pRasEntry->szDeviceName),
  368. szFileName);
  369. }
  370. }
  371. //+---------------------------------------------------------------------------
  372. //
  373. // Function: ImportServerInfo
  374. //
  375. // Purpose: This function imports the server type name and settings
  376. //
  377. // Arguments:
  378. // szFileName [in] The .DUN file name
  379. //
  380. // Returns:
  381. //
  382. VOID ImportServerInfo(RASENTRY * pRasEntry,
  383. IN LPWSTR szFileName)
  384. {
  385. HRESULT hr = S_OK;
  386. WCHAR szValue[MAXLONGLEN];
  387. WCHAR szYesNo[MAXLONGLEN];
  388. DWORD dwRet;
  389. // Get the server type: PPP, SLIP or RAS
  390. //
  391. if (GetPrivateProfileString(c_szServerSection,
  392. c_szServerType,
  393. c_szEmpty,
  394. szValue,
  395. celems(szValue),
  396. szFileName))
  397. {
  398. if (!lstrcmpiW(szValue, c_szPPP))
  399. {
  400. pRasEntry->dwFramingProtocol = RASFP_Ppp;
  401. }
  402. else if (!lstrcmpiW(szValue, c_szSLIP))
  403. {
  404. pRasEntry->dwFramingProtocol = RASFP_Slip;
  405. }
  406. else if (!lstrcmpiW(szValue, c_szRAS))
  407. {
  408. pRasEntry->dwFramingProtocol = RASFP_Ras;
  409. }
  410. }
  411. // SW_Compress
  412. //
  413. if (GetPrivateProfileString(c_szServerSection,
  414. c_szSWCompress,
  415. c_szEmpty,
  416. szYesNo,
  417. celems(szYesNo),
  418. szFileName))
  419. {
  420. if (!lstrcmpiW(szYesNo, c_szYes))
  421. {
  422. pRasEntry->dwfOptions |= RASEO_SwCompression;
  423. };
  424. };
  425. // PW_Encrypt
  426. //
  427. if (GetPrivateProfileString(c_szServerSection,
  428. c_szPWEncrypt,
  429. c_szEmpty,
  430. szYesNo,
  431. celems(szYesNo),
  432. szFileName))
  433. {
  434. if (!lstrcmpiW(szYesNo, c_szYes))
  435. {
  436. pRasEntry->dwfOptions |= RASEO_RequireEncryptedPw;
  437. };
  438. };
  439. // Network_Logon
  440. //
  441. if (GetPrivateProfileString(c_szServerSection,
  442. c_szNetLogon,
  443. c_szEmpty,
  444. szYesNo,
  445. celems(szYesNo),
  446. szFileName))
  447. {
  448. if (!lstrcmpiW(szYesNo, c_szYes))
  449. {
  450. pRasEntry->dwfOptions |= RASEO_NetworkLogon;
  451. };
  452. };
  453. // SW_Encrypt
  454. //
  455. // set both RASEO_RequireMsEncryptedPw and RASEO_RequireDataEncryption
  456. // if SW_Encrypt is TRUE
  457. //
  458. if (GetPrivateProfileString(c_szServerSection,
  459. c_szSWEncrypt,
  460. c_szEmpty,
  461. szYesNo,
  462. celems(szYesNo),
  463. szFileName))
  464. {
  465. if (!lstrcmpiW(szYesNo, c_szYes))
  466. {
  467. pRasEntry->dwfOptions |= RASEO_RequireMsEncryptedPw;
  468. pRasEntry->dwfOptions |= RASEO_RequireDataEncryption;
  469. };
  470. };
  471. // Get the network protocols to negotiate
  472. //
  473. if (GetPrivateProfileString(c_szServerSection,
  474. c_szNetBEUI,
  475. c_szEmpty,
  476. szYesNo,
  477. celems(szYesNo),
  478. szFileName))
  479. {
  480. if (!lstrcmpiW(szYesNo, c_szYes))
  481. {
  482. pRasEntry->dwfNetProtocols |= RASNP_NetBEUI;
  483. };
  484. };
  485. if (GetPrivateProfileString(c_szServerSection,
  486. c_szIPX,
  487. c_szEmpty,
  488. szYesNo,
  489. celems(szYesNo),
  490. szFileName))
  491. {
  492. if (!lstrcmpiW(szYesNo, c_szYes))
  493. {
  494. pRasEntry->dwfNetProtocols |= RASNP_Ipx;
  495. };
  496. };
  497. if (GetPrivateProfileString(c_szServerSection,
  498. c_szIP,
  499. c_szEmpty,
  500. szYesNo,
  501. celems(szYesNo),
  502. szFileName))
  503. {
  504. if (!lstrcmpiW(szYesNo, c_szYes))
  505. {
  506. pRasEntry->dwfNetProtocols |= RASNP_Ip;
  507. };
  508. };
  509. }
  510. //+---------------------------------------------------------------------------
  511. //
  512. // Function: ImportIPInfo
  513. //
  514. // Purpose: This function imports the device info
  515. //
  516. // Arguments:
  517. // szFileName [in] The .DUN file name
  518. //
  519. // Returns:
  520. //
  521. VOID ImportIPInfo(RASENTRY * pRasEntry,
  522. IN LPWSTR szFileName)
  523. {
  524. WCHAR szIPAddr[MAXIPADDRLEN];
  525. WCHAR szYesNo[MAXLONGLEN];
  526. // Import IP address information
  527. //
  528. if (GetPrivateProfileString(c_szIPSection,
  529. c_szIPSpec,
  530. c_szEmpty,
  531. szYesNo,
  532. celems(szYesNo),
  533. szFileName))
  534. {
  535. if (!lstrcmpiW(szYesNo, c_szYes))
  536. {
  537. pRasEntry->dwfOptions |= RASEO_SpecificIpAddr;
  538. // Get the IP address
  539. //
  540. if (GetPrivateProfileString(c_szIPSection,
  541. c_szIPAddress,
  542. c_szEmpty,
  543. szIPAddr,
  544. celems(szIPAddr),
  545. szFileName))
  546. {
  547. SzToRasIpAddr(szIPAddr, &(pRasEntry->ipaddr));
  548. };
  549. }
  550. };
  551. // Import Server address information
  552. //
  553. if (GetPrivateProfileString(c_szIPSection,
  554. c_szServerSpec,
  555. c_szEmpty,
  556. szYesNo,
  557. celems(szYesNo),
  558. szFileName))
  559. {
  560. if (!lstrcmpiW(szYesNo, c_szYes))
  561. {
  562. // The import file has server address specified, get the server address
  563. //
  564. pRasEntry->dwfOptions |= RASEO_SpecificNameServers;
  565. if (GetPrivateProfileString(c_szIPSection,
  566. c_szDNSAddress,
  567. c_szEmpty,
  568. szIPAddr,
  569. celems(szIPAddr),
  570. szFileName))
  571. {
  572. SzToRasIpAddr(szIPAddr, &(pRasEntry->ipaddrDns));
  573. };
  574. if (GetPrivateProfileString(c_szIPSection,
  575. c_szDNSAltAddress,
  576. c_szEmpty,
  577. szIPAddr,
  578. celems(szIPAddr),
  579. szFileName))
  580. {
  581. SzToRasIpAddr(szIPAddr, &(pRasEntry->ipaddrDnsAlt));
  582. };
  583. if (GetPrivateProfileString(c_szIPSection,
  584. c_szWINSAddress,
  585. c_szEmpty,
  586. szIPAddr,
  587. celems(szIPAddr),
  588. szFileName))
  589. {
  590. SzToRasIpAddr(szIPAddr, &(pRasEntry->ipaddrWins));
  591. };
  592. if (GetPrivateProfileString(c_szIPSection,
  593. c_szWINSAltAddress,
  594. c_szEmpty,
  595. szIPAddr,
  596. celems(szIPAddr),
  597. szFileName))
  598. {
  599. SzToRasIpAddr(szIPAddr, &(pRasEntry->ipaddrWinsAlt));
  600. };
  601. }
  602. };
  603. // Header compression and the gateway settings
  604. //
  605. if (GetPrivateProfileString(c_szIPSection,
  606. c_szIPCompress,
  607. c_szEmpty,
  608. szYesNo,
  609. celems(szYesNo),
  610. szFileName))
  611. {
  612. if (!lstrcmpiW(szYesNo, c_szYes))
  613. {
  614. pRasEntry->dwfOptions |= RASEO_IpHeaderCompression;
  615. }
  616. };
  617. if (GetPrivateProfileString(c_szIPSection,
  618. c_szRemoteGateway,
  619. c_szEmpty,
  620. szYesNo,
  621. celems(szYesNo),
  622. szFileName))
  623. {
  624. if (!lstrcmpiW(szYesNo, c_szYes))
  625. {
  626. pRasEntry->dwfOptions |= RASEO_RemoteDefaultGateway;
  627. }
  628. };
  629. }
  630. VOID SzToRasIpAddr(IN LPWSTR szIPAddress,
  631. OUT RASIPADDR * pIpAddr)
  632. {
  633. list<tstring *> listFields;
  634. ConvertStringToColString(szIPAddress,
  635. CH_DOT,
  636. listFields);
  637. list<tstring *>::const_iterator iter = listFields.begin();
  638. if (listFields.size() == NUM_IP_FIELDS)
  639. {
  640. // Go through each field and get the number value
  641. BYTE a = _wtol((*iter++)->c_str());
  642. BYTE b = _wtol((*iter++)->c_str());
  643. BYTE c = _wtol((*iter++)->c_str());
  644. BYTE d = _wtol((*iter++)->c_str());
  645. // validate the address
  646. if ((a >= MIN_IP_VALUE) && (a <= MAX_IP_VALUE) &&
  647. (b >= MIN_IP_VALUE) && (b <= MAX_IP_VALUE) &&
  648. (c >= MIN_IP_VALUE) && (c <= MAX_IP_VALUE) &&
  649. (d >= MIN_IP_VALUE) && (d <= MAX_IP_VALUE))
  650. {
  651. pIpAddr->a = a;
  652. pIpAddr->b = b;
  653. pIpAddr->c = c;
  654. pIpAddr->d = d;
  655. }
  656. }
  657. FreeCollectionAndItem(listFields);
  658. }