xref: /haiku/src/add-ons/network_settings/dnsclient/DNSSettingsView.cpp (revision a127b88ecbfab58f64944c98aa47722a18e363b2)
1 /*
2  * Copyright 2014-2015 Haiku Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Adrien Destugues, pulkomandy@pulkomandy.tk
7  */
8 
9 
10 #include "DNSSettingsView.h"
11 
12 #include <arpa/inet.h>
13 #include <netinet/in.h>
14 #include <resolv.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <sys/socket.h>
18 
19 #include <Box.h>
20 #include <Button.h>
21 #include <Catalog.h>
22 #include <ControlLook.h>
23 #include <File.h>
24 #include <FindDirectory.h>
25 #include <LayoutBuilder.h>
26 #include <ListView.h>
27 #include <Path.h>
28 #include <SeparatorView.h>
29 #include <ScrollView.h>
30 #include <StringView.h>
31 
32 #include "IPAddressControl.h"
33 
34 
35 static const int32 kMsgAddServer = 'adds';
36 static const int32 kMsgDeleteServer = 'dels';
37 static const int32 kMsgSelectServer = 'sels';
38 static const int32 kMsgMoveUp = 'mvup';
39 static const int32 kMsgMoveDown = 'mvdn';
40 static const int32 kMsgApply = 'aply';
41 
42 
43 #undef B_TRANSLATION_CONTEXT
44 #define B_TRANSLATION_CONTEXT "DNSSettingsView"
45 
46 
47 DNSSettingsView::DNSSettingsView(BNetworkSettingsItem* item)
48 	:
49 	BView("dns", 0),
50 	fItem(item)
51 {
52 	BStringView* titleView = new BStringView("title",
53 		B_TRANSLATE("DNS settings"));
54 	titleView->SetFont(be_bold_font);
55 	titleView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
56 
57 	fServerListView = new BListView("nameservers");
58 	fServerListView->SetSelectionMessage(new BMessage(kMsgSelectServer));
59 	const char* serverLabel = B_TRANSLATE("Server:");
60 	fTextControl = new IPAddressControl(AF_UNSPEC, serverLabel, "server");
61 	fTextControl->SetExplicitMinSize(BSize(fTextControl->StringWidth("5") * 16
62 		+ fTextControl->StringWidth(serverLabel), B_SIZE_UNSET));
63 
64 	fAddButton = new BButton(B_TRANSLATE("Add"), new BMessage(kMsgAddServer));
65 	fAddButton->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
66 	fUpButton = new BButton(B_TRANSLATE("Move up"), new BMessage(kMsgMoveUp));
67 	fUpButton->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
68 	fUpButton->SetEnabled(false);
69 	fDownButton = new BButton(B_TRANSLATE("Move down"),
70 		new BMessage(kMsgMoveDown));
71 	fDownButton->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
72 	fDownButton->SetEnabled(false);
73 	fRemoveButton = new BButton(B_TRANSLATE("Remove"),
74 		new BMessage(kMsgDeleteServer));
75 	fRemoveButton->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
76 	fRemoveButton->SetEnabled(false);
77 	fDomain = new BTextControl(B_TRANSLATE("Domain:"), "", NULL);
78 	fApplyButton = new BButton(B_TRANSLATE("Apply"), new BMessage(kMsgApply));
79 
80 	float spacing = be_control_look->DefaultItemSpacing();
81 
82 	BGridView* serviceGridView = new BGridView();
83 	BLayoutBuilder::Grid<>(serviceGridView)
84 		.Add(fTextControl, 0, 0)
85 		.Add(fAddButton, 1, 0)
86 		.Add(new BScrollView("scroll", fServerListView, 0, false, true),
87 			0, 1, 1, 3)
88 		.Add(fUpButton, 1, 1)
89 		.Add(fDownButton, 1, 2)
90 		.Add(fRemoveButton, 1, 3)
91 		.SetColumnWeight(0, 10.f);
92 
93 	BLayoutBuilder::Group<>(this, B_VERTICAL)
94 		.Add(titleView)
95 		.Add(serviceGridView)
96 		.Add(new BSeparatorView(B_HORIZONTAL))
97 		.Add(fDomain)
98 		.AddStrut(spacing)
99 		.AddGroup(B_HORIZONTAL)
100 			.AddGlue()
101 			.Add(fApplyButton);
102 
103 	_LoadDNSConfiguration();
104 }
105 
106 
107 DNSSettingsView::~DNSSettingsView()
108 {
109 }
110 
111 
112 status_t
113 DNSSettingsView::Revert()
114 {
115 	int i;
116 	for (i = 0; i < fRevertList.CountStrings(); i++) {
117 		BStringItem* item = static_cast<BStringItem*>(
118 			fServerListView->ItemAt(i));
119 		if (item == NULL) {
120 			item = new BStringItem("");
121 			fServerListView->AddItem(item);
122 		}
123 
124 		item->SetText(fRevertList.StringAt(i));
125 	}
126 
127 	// Now remove any extra item
128 	for (; i < fServerListView->CountItems(); i++)
129 		delete fServerListView->RemoveItem(i);
130 
131 	return B_OK;
132 }
133 
134 
135 bool
136 DNSSettingsView::IsRevertable() const
137 {
138 	// TODO
139 	return false;
140 }
141 
142 
143 void
144 DNSSettingsView::AttachedToWindow()
145 {
146 	fAddButton->SetTarget(this);
147 	fRemoveButton->SetTarget(this);
148 	fUpButton->SetTarget(this);
149 	fDownButton->SetTarget(this);
150 
151 	fServerListView->SetTarget(this);
152 
153 	fTextControl->SetTarget(this);
154 
155 	fApplyButton->SetTarget(this);
156 }
157 
158 
159 void
160 DNSSettingsView::MessageReceived(BMessage* message)
161 {
162 	switch (message->what) {
163 		case kMsgAddServer:
164 		{
165 			const char* address = fTextControl->Text();
166 			fServerListView->AddItem(new BStringItem(address));
167 			break;
168 		}
169 		case kMsgDeleteServer:
170 			delete fServerListView->RemoveItem(
171 				fServerListView->CurrentSelection());
172 			break;
173 
174 		case kMsgMoveUp:
175 		{
176 			int index = fServerListView->CurrentSelection();
177 			if (index > 0)
178 				fServerListView->SwapItems(index, index - 1);
179 			break;
180 		}
181 		case kMsgMoveDown:
182 		{
183 			int index = fServerListView->CurrentSelection();
184 			if (index < fServerListView->CountItems() - 1)
185 				fServerListView->SwapItems(index, index + 1);
186 			break;
187 		}
188 		case kMsgSelectServer:
189 		{
190 			bool enabled = false;
191 			if (fServerListView->CurrentSelection() > -1)
192 				enabled = true;
193 
194 			fUpButton->SetEnabled(enabled);
195 			fDownButton->SetEnabled(enabled);
196 			fRemoveButton->SetEnabled(enabled);
197 			break;
198 		}
199 		case kMsgApply:
200 			if (_SaveDNSConfiguration() == B_OK)
201 				fItem->NotifySettingsUpdated();
202 			break;
203 
204 		default:
205 			BView::MessageReceived(message);
206 			break;
207 	}
208 }
209 
210 
211 status_t
212 DNSSettingsView::_LoadDNSConfiguration()
213 {
214 	if (res_init() != 0)
215 		return B_ERROR;
216 
217 	struct __res_state state;
218 	memset(&state, 0, sizeof(struct __res_state));
219 
220 	if (res_ninit(&state) != 0)
221 		return B_ERROR;
222 
223 	for (int i = 0; i < state.nscount; i++) {
224 		char* address = inet_ntoa(state.nsaddr_list[i].sin_addr);
225 		fServerListView->AddItem(new BStringItem(address));
226 		fRevertList.Add(address);
227 	}
228 
229 	fDomain->SetText(state.dnsrch[0]);
230 
231 	res_nclose(&state);
232 	return B_OK;
233 }
234 
235 
236 status_t
237 DNSSettingsView::_SaveDNSConfiguration()
238 {
239 	BPath path;
240 	status_t status;
241 	status = find_directory(B_SYSTEM_SETTINGS_DIRECTORY, &path);
242 	if (status != B_OK)
243 		return status;
244 
245 	path.Append("network/resolv.conf");
246 
247 	BFile file(path.Path(), B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY);
248 	if (file.InitCheck() != B_OK) {
249 		fprintf(stderr, "failed to open %s for writing: %s\n", path.Path(),
250 			strerror(file.InitCheck()));
251 		return file.InitCheck();
252 	}
253 
254 	BString content("# Static DNS entries\n# Generated by Network preferences\n");
255 
256 	for (int i = 0; i < fServerListView->CountItems(); i++) {
257 		BString item = ((BStringItem*)fServerListView->ItemAt(i))->Text();
258 		if (item.Length() > 0)
259 			content << "nameserver\t" << item.String() << "\n";
260 	}
261 
262 	if (strlen(fDomain->Text()) > 0)
263 		content << "domain\t" << fDomain->Text() << "\n";
264 
265 	content << "# Dynamic DNS entries\n# may be altered by DHCP\n";
266 
267 	return file.Write(content.String(), content.Length());
268 }
269