xref: /haiku/src/preferences/network/InterfaceAddressView.cpp (revision 8ff235aa286143a295644a3068ad485d3c9d8133)
1 /*
2  * Copyright 2004-2015 Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Alexander von Gluck, kallisti5@unixzen.com
7  *		John Scipione, jscipione@gmail.com
8  */
9 
10 
11 #include "InterfaceAddressView.h"
12 
13 #include <stdio.h>
14 
15 #include <Button.h>
16 #include <Catalog.h>
17 #include <ControlLook.h>
18 #include <LayoutBuilder.h>
19 #include <MenuItem.h>
20 #include <MenuField.h>
21 #include <PopUpMenu.h>
22 #include <Screen.h>
23 #include <Size.h>
24 #include <StringView.h>
25 #include <TextControl.h>
26 
27 #include "IPAddressControl.h"
28 
29 
30 #undef B_TRANSLATION_CONTEXT
31 #define B_TRANSLATION_CONTEXT "IntefaceAddressView"
32 
33 
34 const uint32 kModeAuto = 'iato';
35 const uint32 kModeStatic = 'istc';
36 const uint32 kModeDisabled = 'ioff';
37 const uint32 kMsgApply = 'aply';
38 
39 
40 // #pragma mark - InterfaceAddressView
41 
42 
InterfaceAddressView(int family,const char * interface,BNetworkSettings & settings)43 InterfaceAddressView::InterfaceAddressView(int family,
44 	const char* interface, BNetworkSettings& settings)
45 	:
46 	BGroupView(B_VERTICAL),
47 	fFamily(family),
48 	fInterface(interface),
49 	fSettings(settings)
50 {
51 	SetLayout(new BGroupLayout(B_VERTICAL));
52 
53 	// Create our controls
54 	fModePopUpMenu = new BPopUpMenu("modes");
55 
56 	if (fFamily == AF_INET) {
57 		fModePopUpMenu->AddItem(new BMenuItem(B_TRANSLATE("DHCP"),
58 			new BMessage(kModeAuto)));
59 	}
60 
61 	if (fFamily == AF_INET6) {
62 		// Automatic can be DHCPv6 or Router Advertisements
63 		fModePopUpMenu->AddItem(new BMenuItem(B_TRANSLATE("Automatic"),
64 			new BMessage(kModeAuto)));
65 	}
66 
67 	fModePopUpMenu->AddItem(new BMenuItem(B_TRANSLATE("Static"),
68 		new BMessage(kModeStatic)));
69 	fModePopUpMenu->AddSeparatorItem();
70 	fModePopUpMenu->AddItem(new BMenuItem(B_TRANSLATE("Disabled"),
71 		new BMessage(kModeDisabled)));
72 
73 	fModeField = new BMenuField(B_TRANSLATE("Mode:"), fModePopUpMenu);
74 	fModeField->SetToolTip(
75 		B_TRANSLATE("The method for obtaining an IP address"));
76 
77 	float minimumWidth = be_control_look->DefaultItemSpacing() * 15;
78 
79 	fAddressField = new IPAddressControl(fFamily, B_TRANSLATE("IP address:"),
80 		NULL);
81 	fAddressField->SetToolTip(B_TRANSLATE("Your IP address"));
82 	fAddressField->TextView()->SetExplicitMinSize(
83 		BSize(minimumWidth, B_SIZE_UNSET));
84 	fAddressField->SetAllowEmpty(false);
85 	fNetmaskField = new IPAddressControl(fFamily, B_TRANSLATE("Netmask:"),
86 		NULL);
87 	fNetmaskField->SetToolTip(B_TRANSLATE(
88 		"The netmask defines your local network"));
89 	fNetmaskField->TextView()->SetExplicitMinSize(
90 		BSize(minimumWidth, B_SIZE_UNSET));
91 	fGatewayField = new IPAddressControl(fFamily, B_TRANSLATE("Gateway:"),
92 		NULL);
93 	fGatewayField->SetToolTip(B_TRANSLATE("Your gateway to the internet"));
94 	fGatewayField->TextView()->SetExplicitMinSize(
95 		BSize(minimumWidth, B_SIZE_UNSET));
96 
97 	fApplyButton = new BButton("apply", B_TRANSLATE("Apply"),
98 		new BMessage(kMsgApply));
99 
100 	fSettings.GetInterface(interface, fOriginalSettings);
101 	_UpdateFields();
102 
103 	BLayoutBuilder::Group<>(this)
104 		.AddGrid()
105 			.AddMenuField(fModeField, 0, 0, B_ALIGN_RIGHT)
106 			.AddTextControl(fAddressField, 0, 1, B_ALIGN_RIGHT)
107 			.AddTextControl(fNetmaskField, 0, 2, B_ALIGN_RIGHT)
108 			.AddTextControl(fGatewayField, 0, 3, B_ALIGN_RIGHT)
109 		.End()
110 		.AddGroup(B_HORIZONTAL)
111 			.AddGlue()
112 			.Add(fApplyButton)
113 		.End()
114 		.AddGlue();
115 }
116 
117 
~InterfaceAddressView()118 InterfaceAddressView::~InterfaceAddressView()
119 {
120 }
121 
122 
123 // #pragma mark - InterfaceAddressView virtual methods
124 
125 
126 void
AttachedToWindow()127 InterfaceAddressView::AttachedToWindow()
128 {
129 	fModePopUpMenu->SetTargetForItems(this);
130 	fApplyButton->SetTarget(this);
131 }
132 
133 
134 void
MessageReceived(BMessage * message)135 InterfaceAddressView::MessageReceived(BMessage* message)
136 {
137 	switch (message->what) {
138 		case kModeAuto:
139 		case kModeStatic:
140 		case kModeDisabled:
141 			if (message->what == fLastMode)
142 				break;
143 
144 			_SetModeField(message->what);
145 			if (message->what != kModeStatic)
146 				_UpdateSettings();
147 			break;
148 
149 		case kMsgApply:
150 			_UpdateSettings();
151 			break;
152 
153 		default:
154 			BView::MessageReceived(message);
155 	}
156 }
157 
158 
159 // #pragma mark - InterfaceAddressView public methods
160 
161 
162 status_t
Revert()163 InterfaceAddressView::Revert()
164 {
165 	return fSettings.AddInterface(fOriginalSettings);
166 }
167 
168 
169 bool
IsRevertable() const170 InterfaceAddressView::IsRevertable() const
171 {
172 	BMessage settings;
173 	fSettings.GetInterface(fInterface.Name(), settings);
174 
175 	return !settings.HasSameData(fOriginalSettings);
176 }
177 
178 
179 void
ConfigurationUpdated(const BMessage & message)180 InterfaceAddressView::ConfigurationUpdated(const BMessage& message)
181 {
182 	const char* interface = message.GetString("interface", NULL);
183 	if (interface == NULL || strcmp(interface, fInterface.Name()) != 0)
184 		return;
185 
186 	_UpdateFields();
187 }
188 
189 
190 // #pragma mark - InterfaceAddressView private methods
191 
192 
193 void
_EnableFields(bool enable)194 InterfaceAddressView::_EnableFields(bool enable)
195 {
196 	fAddressField->SetEnabled(enable);
197 	fNetmaskField->SetEnabled(enable);
198 	fGatewayField->SetEnabled(enable);
199 	fApplyButton->SetEnabled(enable);
200 }
201 
202 
203 /*!	Updates the UI to match the current interface configuration.
204 
205 	The interface settings may be consulted to determine if the
206 	automatic configuration has been specified, if there was no
207 	configuration yet.
208 */
209 void
_UpdateFields()210 InterfaceAddressView::_UpdateFields()
211 {
212 	BMessage interfaceSettings;
213 	fSettings.GetInterface(fInterface.Name(), interfaceSettings);
214 
215 	bool autoConfigure = interfaceSettings.IsEmpty();
216 	if (!autoConfigure) {
217 		BNetworkInterfaceSettings settings(interfaceSettings);
218 		autoConfigure = settings.IsAutoConfigure(fFamily);
219 	}
220 
221 	BNetworkInterfaceAddress address;
222 	status_t status = B_ERROR;
223 
224 	int32 index = fInterface.FindFirstAddress(fFamily);
225 	if (index >= 0)
226 		status = fInterface.GetAddressAt(index, address);
227 	if (!autoConfigure && (index < 0 || status != B_OK
228 			|| address.Address().IsEmpty())) {
229 		_SetModeField(kModeDisabled);
230 		return;
231 	}
232 
233 	if (autoConfigure)
234 		_SetModeField(kModeAuto);
235 	else
236 		_SetModeField(kModeStatic);
237 
238 	fAddressField->SetText(address.Address().ToString());
239 	fNetmaskField->SetText(address.Mask().ToString());
240 
241 	BNetworkAddress gateway;
242 	if (fInterface.GetDefaultGateway(fFamily, gateway) == B_OK)
243 		fGatewayField->SetText(gateway.ToString());
244 	else
245 		fGatewayField->SetText(NULL);
246 }
247 
248 
249 void
_SetModeField(uint32 mode)250 InterfaceAddressView::_SetModeField(uint32 mode)
251 {
252 	BMenuItem* item = fModePopUpMenu->FindItem(mode);
253 	if (item != NULL)
254 		item->SetMarked(true);
255 
256 	_EnableFields(mode == kModeStatic);
257 
258 	if (mode == kModeDisabled) {
259 		fAddressField->SetText(NULL);
260 		fNetmaskField->SetText(NULL);
261 		fGatewayField->SetText(NULL);
262 	} else if (mode == kModeStatic)
263 		fAddressField->MakeFocus(true);
264 
265 	fLastMode = mode;
266 }
267 
268 
269 /*!	Updates the current settings from the controls. */
270 void
_UpdateSettings()271 InterfaceAddressView::_UpdateSettings()
272 {
273 	BMessage interface;
274 	fSettings.GetInterface(fInterface.Name(), interface);
275 	BNetworkInterfaceSettings settings(interface);
276 
277 	settings.SetName(fInterface.Name());
278 
279 	// Remove previous address for family
280 
281 	int32 index = settings.FindFirstAddress(fFamily);
282 	if (index < 0)
283 		index = settings.FindFirstAddress(AF_UNSPEC);
284 	if (index >= 0 && index < settings.CountAddresses()) {
285 		BNetworkInterfaceAddressSettings& address = settings.AddressAt(index);
286 		_ConfigureAddress(address);
287 	} else {
288 		BNetworkInterfaceAddressSettings address;
289 		_ConfigureAddress(address);
290 		settings.AddAddress(address);
291 	}
292 
293 	interface.MakeEmpty();
294 
295 	// TODO: better error reporting!
296 	status_t status = settings.GetMessage(interface);
297 	if (status == B_OK)
298 		fSettings.AddInterface(interface);
299 	else
300 		fprintf(stderr, "Could not add interface: %s\n", strerror(status));
301 }
302 
303 
304 uint32
_Mode() const305 InterfaceAddressView::_Mode() const
306 {
307 	uint32 mode = kModeAuto;
308 	BMenuItem* item = fModePopUpMenu->FindMarked();
309 	if (item != NULL)
310 		mode = item->Message()->what;
311 
312 	return mode;
313 }
314 
315 
316 void
_ConfigureAddress(BNetworkInterfaceAddressSettings & settings)317 InterfaceAddressView::_ConfigureAddress(
318 	BNetworkInterfaceAddressSettings& settings)
319 {
320 	uint32 mode = _Mode();
321 
322 	settings.SetFamily(fFamily);
323 	settings.SetAutoConfigure(mode == kModeAuto);
324 
325 	settings.Address().Unset();
326 	settings.Mask().Unset();
327 	settings.Peer().Unset();
328 	settings.Broadcast().Unset();
329 	settings.Gateway().Unset();
330 
331 	if (mode == kModeStatic) {
332 		_SetAddress(settings.Address(), fAddressField->Text());
333 		_SetAddress(settings.Mask(), fNetmaskField->Text());
334 		_SetAddress(settings.Gateway(), fGatewayField->Text());
335 	}
336 }
337 
338 
339 void
_SetAddress(BNetworkAddress & address,const char * text)340 InterfaceAddressView::_SetAddress(BNetworkAddress& address, const char* text)
341 {
342 	BString string(text);
343 	string.Trim();
344 	if (string.IsEmpty())
345 		return;
346 
347 	address.SetTo(string.String(), static_cast<uint16>(0),
348 		B_NO_ADDRESS_RESOLUTION);
349 }
350