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
34const uint32 kModeAuto = 'iato';
35const uint32 kModeStatic = 'istc';
36const uint32 kModeDisabled = 'ioff';
37const uint32 kMsgApply = 'aply';
38
39
40// #pragma mark - InterfaceAddressView
41
42
43InterfaceAddressView::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
118InterfaceAddressView::~InterfaceAddressView()
119{
120}
121
122
123// #pragma mark - InterfaceAddressView virtual methods
124
125
126void
127InterfaceAddressView::AttachedToWindow()
128{
129	fModePopUpMenu->SetTargetForItems(this);
130	fApplyButton->SetTarget(this);
131}
132
133
134void
135InterfaceAddressView::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
162status_t
163InterfaceAddressView::Revert()
164{
165	return fSettings.AddInterface(fOriginalSettings);
166}
167
168
169bool
170InterfaceAddressView::IsRevertable() const
171{
172	BMessage settings;
173	fSettings.GetInterface(fInterface.Name(), settings);
174
175	return !settings.HasSameData(fOriginalSettings);
176}
177
178
179void
180InterfaceAddressView::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
193void
194InterfaceAddressView::_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*/
209void
210InterfaceAddressView::_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
249void
250InterfaceAddressView::_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. */
270void
271InterfaceAddressView::_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
304uint32
305InterfaceAddressView::_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
316void
317InterfaceAddressView::_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
339void
340InterfaceAddressView::_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