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