move more dlls
[reactos.git] / reactos / lib / cpl / ncpa / tcpip_properties.c
1 /*
2 * PROJECT: ReactOS Network Control Panel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: lib/cpl/system/tcpip_properties.c
5 * PURPOSE: ReactOS Network Control Panel
6 * COPYRIGHT: Copyright 2004 Gero Kuehn (reactos.filter@gkware.com)
7 * Copyright 2006 Ge van Geldorp <gvg@reactos.org>
8 */
9
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <stdarg.h>
13 #include <tchar.h>
14 #include <windows.h>
15 #include <iptypes.h>
16 #include <iphlpapi.h>
17 #include <commctrl.h>
18 #include <dhcpcapi.h>
19 #include <prsht.h>
20
21
22 #ifdef _MSC_VER
23 #include <cpl.h>
24 #else
25
26 // this is missing on reactos...
27 #ifndef IPM_SETADDRESS
28 #define IPM_SETADDRESS (WM_USER+101)
29 #endif
30
31 #endif
32
33 #include "resource.h"
34 #include "ncpa.h"
35
36 #define NDEBUG
37 #include <debug.h>
38
39 typedef struct _TCPIP_PROPERTIES_DATA {
40 DWORD AdapterIndex;
41 char *AdapterName;
42 BOOL DhcpEnabled;
43 DWORD IpAddress;
44 DWORD SubnetMask;
45 DWORD Gateway;
46 DWORD Dns1;
47 DWORD Dns2;
48 BOOL OldDhcpEnabled;
49 DWORD OldIpAddress;
50 DWORD OldSubnetMask;
51 DWORD OldGateway;
52 DWORD OldDns1;
53 DWORD OldDns2;
54 } TCPIP_PROPERTIES_DATA, *PTCPIP_PROPERTIES_DATA;
55
56 void InitPropSheetPage(PROPSHEETPAGE *psp, WORD idDlg, DLGPROC DlgProc);
57 DWORD APIENTRY DhcpNotifyConfigChange(LPWSTR ServerName, LPWSTR AdapterName,
58 BOOL NewIpAddress, DWORD IpIndex,
59 DWORD IpAddress, DWORD SubnetMask,
60 int DhcpAction);
61
62
63 static void
64 ManualDNS(HWND Dlg, BOOL Enabled) {
65 CheckDlgButton(Dlg, IDC_FIXEDDNS,
66 Enabled ? BST_CHECKED : BST_UNCHECKED);
67 CheckDlgButton(Dlg, IDC_AUTODNS,
68 Enabled ? BST_UNCHECKED : BST_CHECKED);
69 EnableWindow(GetDlgItem(Dlg, IDC_DNS1), Enabled);
70 EnableWindow(GetDlgItem(Dlg, IDC_DNS2), Enabled);
71 if (! Enabled) {
72 SendDlgItemMessage(Dlg, IDC_DNS1, IPM_CLEARADDRESS, 0, 0);
73 SendDlgItemMessage(Dlg, IDC_DNS2, IPM_CLEARADDRESS, 0, 0);
74 }
75 }
76
77 static void
78 EnableDHCP(HWND Dlg, BOOL Enabled) {
79 CheckDlgButton(Dlg, IDC_USEDHCP, Enabled ? BST_CHECKED : BST_UNCHECKED);
80 CheckDlgButton(Dlg, IDC_NODHCP, Enabled ? BST_UNCHECKED : BST_CHECKED);
81 EnableWindow(GetDlgItem(Dlg, IDC_IPADDR), ! Enabled);
82 EnableWindow(GetDlgItem(Dlg, IDC_SUBNETMASK), ! Enabled);
83 EnableWindow(GetDlgItem(Dlg, IDC_DEFGATEWAY), ! Enabled);
84 EnableWindow(GetDlgItem(Dlg, IDC_AUTODNS), Enabled);
85 if (Enabled) {
86 SendDlgItemMessage(Dlg, IDC_IPADDR, IPM_CLEARADDRESS, 0, 0);
87 SendDlgItemMessage(Dlg, IDC_SUBNETMASK, IPM_CLEARADDRESS, 0, 0);
88 SendDlgItemMessage(Dlg, IDC_DEFGATEWAY, IPM_CLEARADDRESS, 0, 0);
89 } else {
90 ManualDNS(Dlg, TRUE);
91 }
92 }
93
94 static void
95 ShowError(HWND Parent, UINT MsgId)
96 {
97 WCHAR Error[32], Msg[64];
98
99 if (0 == LoadStringW((HINSTANCE) GetWindowLongPtrW(Parent, GWLP_HINSTANCE),
100 IDS_ERROR, Error, sizeof(Error) / sizeof(Error[0]))) {
101 wcscpy(Error, L"Error");
102 }
103 if (0 == LoadStringW((HINSTANCE) GetWindowLongPtrW(Parent, GWLP_HINSTANCE),
104 MsgId, Msg, sizeof(Msg) / sizeof(Msg[0]))) {
105 wcscpy(Msg, L"Unknown error");
106 }
107 MessageBoxW(Parent, Msg, Error, MB_OK | MB_ICONSTOP);
108 }
109
110 static BOOL
111 ValidateAndStore(HWND Dlg, PTCPIP_PROPERTIES_DATA DlgData)
112 {
113 DWORD IpAddress;
114
115 DlgData->DhcpEnabled = (BST_CHECKED ==
116 IsDlgButtonChecked(Dlg, IDC_USEDHCP));
117 if (! DlgData->DhcpEnabled) {
118 if (4 != SendMessageW(GetDlgItem(Dlg, IDC_IPADDR), IPM_GETADDRESS,
119 0, (LPARAM) &IpAddress)) {
120 ShowError(Dlg, IDS_ENTER_VALID_IPADDRESS);
121 SetFocus(GetDlgItem(Dlg, IDC_IPADDR));
122 return FALSE;
123 }
124 DlgData->IpAddress = htonl(IpAddress);
125 if (4 != SendMessageW(GetDlgItem(Dlg, IDC_SUBNETMASK), IPM_GETADDRESS,
126 0, (LPARAM) &IpAddress)) {
127 ShowError(Dlg, IDS_ENTER_VALID_SUBNET);
128 SetFocus(GetDlgItem(Dlg, IDC_SUBNETMASK));
129 return FALSE;
130 }
131 DlgData->SubnetMask = htonl(IpAddress);
132 if (4 != SendMessageW(GetDlgItem(Dlg, IDC_DEFGATEWAY), IPM_GETADDRESS,
133 0, (LPARAM) &IpAddress)) {
134 DlgData->Gateway = INADDR_NONE;
135 } else {
136 DlgData->Gateway = htonl(IpAddress);
137 }
138 ASSERT(BST_CHECKED == IsDlgButtonChecked(Dlg, IDC_FIXEDDNS));
139 } else {
140 DlgData->IpAddress = INADDR_NONE;
141 DlgData->SubnetMask = INADDR_NONE;
142 DlgData->Gateway = INADDR_NONE;
143 }
144
145 if (BST_CHECKED == IsDlgButtonChecked(Dlg, IDC_FIXEDDNS)) {
146 if (4 != SendMessageW(GetDlgItem(Dlg, IDC_DNS1), IPM_GETADDRESS,
147 0, (LPARAM) &IpAddress)) {
148 DlgData->Dns1 = INADDR_NONE;
149 } else {
150 DlgData->Dns1 = htonl(IpAddress);
151 }
152 if (4 != SendMessageW(GetDlgItem(Dlg, IDC_DNS2), IPM_GETADDRESS,
153 0, (LPARAM) &IpAddress)) {
154 DlgData->Dns2 = INADDR_NONE;
155 } else {
156 DlgData->Dns2 = htonl(IpAddress);
157 }
158 } else {
159 DlgData->Dns1 = INADDR_NONE;
160 DlgData->Dns2 = INADDR_NONE;
161 }
162
163 return TRUE;
164 }
165
166 static BOOL
167 InternTCPIPSettings(HWND Dlg, PTCPIP_PROPERTIES_DATA DlgData) {
168 BOOL Changed;
169 BOOL IpChanged;
170 int DhcpAction;
171 LPWSTR AdapterName;
172
173 if (! ValidateAndStore(Dlg, DlgData)) {
174 /* Should never happen, we should have validated at PSN_KILLACTIVE */
175 ASSERT(FALSE);
176 return FALSE;
177 }
178
179 Changed = FALSE;
180 if (DlgData->DhcpEnabled) {
181 Changed = ! DlgData->OldDhcpEnabled;
182 IpChanged = FALSE;
183 DhcpAction = 1;
184 } else {
185 Changed = DlgData->OldDhcpEnabled ||
186 DlgData->IpAddress != DlgData->OldIpAddress ||
187 DlgData->SubnetMask != DlgData->OldSubnetMask;
188 IpChanged = DlgData->OldDhcpEnabled ||
189 DlgData->IpAddress != DlgData->OldIpAddress;
190 DhcpAction = 2;
191 }
192
193 if (Changed) {
194 AdapterName = HeapAlloc(GetProcessHeap(), 0,
195 (strlen(DlgData->AdapterName) + 1) *
196 sizeof(WCHAR));
197 if (NULL == AdapterName) {
198 ShowError(Dlg, IDS_OUT_OF_MEMORY);
199 return FALSE;
200 }
201 MultiByteToWideChar(CP_THREAD_ACP, 0, DlgData->AdapterName, -1,
202 AdapterName, strlen(DlgData->AdapterName) + 1);
203 if (0 == DhcpNotifyConfigChange(NULL, AdapterName, IpChanged,
204 DlgData->AdapterIndex,
205 DlgData->IpAddress,
206 DlgData->SubnetMask, DhcpAction)) {
207 HeapFree(GetProcessHeap(), 0, AdapterName);
208 ShowError(Dlg, IDS_CANNOT_SAVE_CHANGES);
209 return FALSE;
210 }
211 HeapFree(GetProcessHeap(), 0, AdapterName);
212 }
213
214 /* FIXME Save default gateway and DNS entries */
215 return TRUE;
216 }
217
218 static INT_PTR CALLBACK
219 TCPIPPropertyPageProc(HWND Dlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
220 {
221 LPPROPSHEETPAGEW Page;
222 PTCPIP_PROPERTIES_DATA DlgData;
223 LPNMHDR Nmhdr;
224
225 DlgData = (PTCPIP_PROPERTIES_DATA) GetWindowLongPtrW(Dlg, GWL_USERDATA);
226 switch(uMsg) {
227 case WM_INITDIALOG:
228 Page = (LPPROPSHEETPAGEW) lParam;
229 DlgData = (PTCPIP_PROPERTIES_DATA) Page->lParam;
230 SetWindowLongPtrW(Dlg, GWL_USERDATA, Page->lParam);
231
232 EnableWindow(GetDlgItem(Dlg, IDC_ADVANCED), FALSE);
233
234 EnableDHCP(Dlg, DlgData->OldDhcpEnabled);
235
236 if (! DlgData->OldDhcpEnabled)
237 {
238 if (INADDR_NONE != DlgData->OldIpAddress) {
239 SendDlgItemMessage(Dlg, IDC_IPADDR, IPM_SETADDRESS, 0,
240 ntohl(DlgData->OldIpAddress));
241 }
242 if (INADDR_NONE != DlgData->OldSubnetMask) {
243 SendDlgItemMessage(Dlg, IDC_SUBNETMASK, IPM_SETADDRESS, 0,
244 ntohl(DlgData->OldSubnetMask));
245 }
246 if (INADDR_NONE != DlgData->OldGateway) {
247 SendDlgItemMessage(Dlg, IDC_DEFGATEWAY, IPM_SETADDRESS, 0,
248 ntohl(DlgData->OldGateway));
249 }
250 }
251
252 if (INADDR_NONE != DlgData->OldDns1) {
253 SendDlgItemMessage(Dlg, IDC_DNS1, IPM_SETADDRESS, 0,
254 ntohl(DlgData->OldDns1));
255 if (INADDR_NONE != DlgData->OldDns2) {
256 SendDlgItemMessage(Dlg, IDC_DNS2, IPM_SETADDRESS, 0,
257 ntohl(DlgData->OldDns2));
258 }
259 }
260 ManualDNS(Dlg, INADDR_NONE != DlgData->OldDns1);
261 break;
262
263 case WM_COMMAND:
264 switch(LOWORD(wParam)) {
265 case IDC_FIXEDDNS:
266 ManualDNS(Dlg, TRUE);
267 return TRUE;
268
269 case IDC_AUTODNS:
270 ManualDNS(Dlg, FALSE);
271 return TRUE;
272
273 case IDC_USEDHCP:
274 EnableDHCP(Dlg, TRUE);
275 return TRUE;
276
277 case IDC_NODHCP:
278 EnableDHCP(Dlg, FALSE);
279 return TRUE;
280 }
281 break;
282
283 case WM_NOTIFY:
284 Nmhdr = (LPNMHDR) lParam;
285
286 switch(Nmhdr->code) {
287 case PSN_KILLACTIVE:
288 /* Do validation here, must set FALSE to continue */
289 SetWindowLongPtrW(Dlg, DWL_MSGRESULT,
290 (LONG_PTR) ! ValidateAndStore(Dlg, DlgData));
291 return TRUE;
292
293 case PSN_APPLY:
294 /* Set the IP Address and DNS Information so we won't
295 * be doing all this for nothing */
296 SetWindowLongPtrW(Dlg, DWL_MSGRESULT,
297 InternTCPIPSettings(Dlg, DlgData) ?
298 PSNRET_NOERROR : PSNRET_INVALID);
299 return TRUE;
300 }
301 break;
302 }
303
304 return FALSE;
305 }
306
307 static BOOL
308 LoadDataFromInfo(PTCPIP_PROPERTIES_DATA DlgData, IP_ADAPTER_INFO *Info)
309 {
310 IP_ADDR_STRING *pString;
311 WCHAR RegKey[MAX_PATH];
312 HKEY hKey;
313 char Dns[MAX_PATH];
314 DWORD Size;
315 DWORD Type;
316 char *NextDnsServer;
317
318 DlgData->AdapterName = Info->AdapterName;
319 DlgData->AdapterIndex = Info->Index;
320
321 DlgData->OldDhcpEnabled = Info->DhcpEnabled;
322
323 pString = &Info->IpAddressList;
324 while (NULL != pString->Next) {
325 pString = pString->Next;
326 }
327 DlgData->OldIpAddress = inet_addr(pString->IpAddress.String);
328 DlgData->OldSubnetMask = inet_addr(pString->IpMask.String);
329 pString = &Info->GatewayList;
330 while (NULL != pString->Next) {
331 pString = pString->Next;
332 }
333 DlgData->OldGateway = inet_addr(pString->IpAddress.String);
334
335 DlgData->OldDns1 = INADDR_NONE;
336 DlgData->OldDns2 = INADDR_NONE;
337 swprintf(RegKey,
338 L"SYSTEM\\CurrentControlSet\\Services\\TCPIP\\Parameters\\Interfaces\\%S",
339 Info->AdapterName);
340 if (ERROR_SUCCESS == RegOpenKeyW(HKEY_LOCAL_MACHINE, RegKey, &hKey)) {
341 Size = sizeof(Dns);
342 RegQueryValueExA(hKey, "NameServer", NULL, &Type, (BYTE *)Dns,
343 &Size);
344 RegCloseKey(hKey);
345
346 if ('\0' != Dns[0]) {
347 DlgData->OldDns1 = inet_addr(Dns);
348 NextDnsServer = strchr(Dns, ',');
349 if (NULL != NextDnsServer && '\0' != *NextDnsServer) {
350 DlgData->OldDns2 = inet_addr(NextDnsServer);
351 }
352 }
353 }
354
355 return TRUE;
356 }
357
358 void
359 DisplayTCPIPProperties(HWND hParent, IP_ADAPTER_INFO *pInfo)
360 {
361 PROPSHEETPAGEW psp[1];
362 PROPSHEETHEADERW psh;
363 INITCOMMONCONTROLSEX cce;
364 TCPIP_PROPERTIES_DATA DlgData;
365
366 if (! LoadDataFromInfo(&DlgData, pInfo))
367 {
368 ShowError(hParent, IDS_CANNOT_LOAD_CONFIG);
369 return;
370 }
371
372 cce.dwSize = sizeof(INITCOMMONCONTROLSEX);
373 cce.dwICC = ICC_INTERNET_CLASSES;
374 InitCommonControlsEx(&cce);
375
376 ZeroMemory(&psh, sizeof(PROPSHEETHEADER));
377 psh.dwSize = sizeof(PROPSHEETHEADER);
378 psh.dwFlags = PSH_PROPSHEETPAGE | PSH_NOAPPLYNOW;
379 psh.hwndParent = hParent;
380 psh.hInstance = hApplet;
381 psh.hIcon = LoadIcon(hApplet, MAKEINTRESOURCE(IDI_CPLSYSTEM));
382 psh.pszCaption = NULL;//Caption;
383 psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE);
384 psh.nStartPage = 0;
385 psh.ppsp = psp;
386 psh.pfnCallback = NULL;
387
388 InitPropSheetPage(&psp[0], IDD_TCPIPPROPERTIES, TCPIPPropertyPageProc);
389 psp[0].lParam = (LPARAM) &DlgData;
390
391 if (PropertySheetW(&psh) == -1)
392 {
393 ShowError(hParent, IDS_CANNOT_CREATE_PROPSHEET);
394 }
395
396 return;
397 }