xref: /haiku/src/add-ons/network_settings/dnsclient/DNSSettingsView.cpp (revision 1e60bdeab63fa7a57bc9a55b032052e95a18bd2c)
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 kMsgMoveUp = 'mvup';
38 static const int32 kMsgMoveDown = 'mvdn';
39 static const int32 kMsgApply = 'aply';
40 
41 
42 #undef B_TRANSLATION_CONTEXT
43 #define B_TRANSLATION_CONTEXT "DNSSettingsView"
44 
45 
46 DNSSettingsView::DNSSettingsView(BNetworkSettingsItem* item)
47 	:
48 	BView("dns", 0),
49 	fItem(item)
50 {
51 	BStringView* titleView = new BStringView("title",
52 		B_TRANSLATE("DNS settings"));
53 	titleView->SetFont(be_bold_font);
54 	titleView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
55 
56 	fServerListView = new BListView("nameservers");
57 	const char* serverLabel = B_TRANSLATE("Server:");
58 	fTextControl = new IPAddressControl(AF_UNSPEC, serverLabel, "server");
59 	fTextControl->SetExplicitMinSize(BSize(fTextControl->StringWidth("5") * 16
60 		+ fTextControl->StringWidth(serverLabel), B_SIZE_UNSET));
61 
62 	fAddButton = new BButton(B_TRANSLATE("Add"), new BMessage(kMsgAddServer));
63 	fAddButton->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
64 	fUpButton = new BButton(B_TRANSLATE("Move up"), new BMessage(kMsgMoveUp));
65 	fUpButton->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
66 	fDownButton = new BButton(B_TRANSLATE("Move down"),
67 		new BMessage(kMsgMoveDown));
68 	fDownButton->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
69 	fRemoveButton = new BButton(B_TRANSLATE("Remove"),
70 		new BMessage(kMsgDeleteServer));
71 	fRemoveButton->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
72 	fDomain = new BTextControl(B_TRANSLATE("Domain:"), "", NULL);
73 	fApplyButton = new BButton(B_TRANSLATE("Apply"), new BMessage(kMsgApply));
74 
75 	float spacing = be_control_look->DefaultItemSpacing();
76 
77 	BGridView* serviceGridView = new BGridView();
78 	BLayoutBuilder::Grid<>(serviceGridView)
79 		.Add(fTextControl, 0, 0)
80 		.Add(fAddButton, 1, 0)
81 		.Add(new BScrollView("scroll", fServerListView, 0, false, true),
82 			0, 1, 1, 3)
83 		.Add(fUpButton, 1, 1)
84 		.Add(fDownButton, 1, 2)
85 		.Add(fRemoveButton, 1, 3)
86 		.SetColumnWeight(0, 10.f);
87 
88 	BLayoutBuilder::Group<>(this, B_VERTICAL)
89 		.Add(titleView)
90 		.Add(serviceGridView)
91 		.Add(new BSeparatorView(B_HORIZONTAL))
92 		.Add(fDomain)
93 		.AddStrut(spacing)
94 		.AddGroup(B_HORIZONTAL)
95 			.AddGlue()
96 			.Add(fApplyButton);
97 
98 	_LoadDNSConfiguration();
99 }
100 
101 
102 DNSSettingsView::~DNSSettingsView()
103 {
104 }
105 
106 
107 status_t
108 DNSSettingsView::Revert()
109 {
110 	int i;
111 	for (i = 0; i < fRevertList.CountStrings(); i++) {
112 		BStringItem* item = static_cast<BStringItem*>(
113 			fServerListView->ItemAt(i));
114 		if (item == NULL) {
115 			item = new BStringItem("");
116 			fServerListView->AddItem(item);
117 		}
118 
119 		item->SetText(fRevertList.StringAt(i));
120 	}
121 
122 	// Now remove any extra item
123 	for (; i < fServerListView->CountItems(); i++)
124 		delete fServerListView->RemoveItem(i);
125 
126 	return B_OK;
127 }
128 
129 
130 bool
131 DNSSettingsView::IsRevertable() const
132 {
133 	// TODO
134 	return false;
135 }
136 
137 
138 void
139 DNSSettingsView::AttachedToWindow()
140 {
141 	fAddButton->SetTarget(this);
142 	fRemoveButton->SetTarget(this);
143 	fUpButton->SetTarget(this);
144 	fDownButton->SetTarget(this);
145 
146 	fTextControl->SetTarget(this);
147 
148 	fApplyButton->SetTarget(this);
149 }
150 
151 
152 void
153 DNSSettingsView::MessageReceived(BMessage* message)
154 {
155 	switch (message->what) {
156 		case kMsgAddServer:
157 		{
158 			const char* address = fTextControl->Text();
159 			fServerListView->AddItem(new BStringItem(address));
160 			break;
161 		}
162 		case kMsgDeleteServer:
163 			delete fServerListView->RemoveItem(
164 				fServerListView->CurrentSelection());
165 			break;
166 
167 		case kMsgMoveUp:
168 		{
169 			int index = fServerListView->CurrentSelection();
170 			if (index > 0)
171 				fServerListView->SwapItems(index, index - 1);
172 			break;
173 		}
174 		case kMsgMoveDown:
175 		{
176 			int index = fServerListView->CurrentSelection();
177 			if (index < fServerListView->CountItems() - 1)
178 				fServerListView->SwapItems(index, index + 1);
179 			break;
180 		}
181 		case kMsgApply:
182 			if (_SaveDNSConfiguration() == B_OK)
183 				fItem->NotifySettingsUpdated();
184 			break;
185 
186 		default:
187 			BView::MessageReceived(message);
188 			break;
189 	}
190 }
191 
192 
193 status_t
194 DNSSettingsView::_LoadDNSConfiguration()
195 {
196 	if (res_init() != 0)
197 		return B_ERROR;
198 
199 	res_state state = __res_get_state();
200 
201 	if (state != NULL) {
202 		for (int i = 0; i < state->nscount; i++) {
203 			char* address = inet_ntoa(state->nsaddr_list[i].sin_addr);
204 			fServerListView->AddItem(new BStringItem(address));
205 			fRevertList.Add(address);
206 		}
207 
208 		fDomain->SetText(state->dnsrch[0]);
209 
210 		__res_put_state(state);
211 		return B_OK;
212 	}
213 
214 	return B_ERROR;
215 }
216 
217 
218 status_t
219 DNSSettingsView::_SaveDNSConfiguration()
220 {
221 	BPath path;
222 	status_t status;
223 	status = find_directory(B_SYSTEM_SETTINGS_DIRECTORY, &path);
224 	if (status != B_OK)
225 		return status;
226 
227 	path.Append("network/resolv.conf");
228 
229 	BFile file(path.Path(), B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY);
230 	if (file.InitCheck() != B_OK) {
231 		fprintf(stderr, "failed to open %s for writing: %s\n", path.Path(),
232 			strerror(file.InitCheck()));
233 		return file.InitCheck();
234 	}
235 
236 	BString content("# Static DNS entries\n# Generated by Network preferences\n");
237 
238 	for (int i = 0; i < fServerListView->CountItems(); i++) {
239 		BString item = ((BStringItem*)fServerListView->ItemAt(i))->Text();
240 		if (item.Length() > 0)
241 			content << "nameserver\t" << item.String() << "\n";
242 	}
243 
244 	if (strlen(fDomain->Text()) > 0)
245 		content << "domain\t" << fDomain->Text() << "\n";
246 
247 	content << "# Dynamic DNS entries\n# may be altered by DHCP\n";
248 
249 	return file.Write(content.String(), content.Length());
250 }
251