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