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
DNSSettingsView(BNetworkSettingsItem * item)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
~DNSSettingsView()107 DNSSettingsView::~DNSSettingsView()
108 {
109 }
110
111
112 status_t
Revert()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
IsRevertable() const136 DNSSettingsView::IsRevertable() const
137 {
138 // TODO
139 return false;
140 }
141
142
143 void
AttachedToWindow()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
MessageReceived(BMessage * message)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
_LoadDNSConfiguration()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
_SaveDNSConfiguration()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