1/* 2 * Copyright 2003-2004 Waldemar Kornewald. All rights reserved. 3 * Copyright 2017 Haiku, Inc. All rights reserved. 4 * Distributed under the terms of the MIT License. 5 */ 6 7//----------------------------------------------------------------------- 8// PPPoEAddon saves the loaded settings. 9// PPPoEView saves the current settings. 10//----------------------------------------------------------------------- 11 12#include "PPPoEAddon.h" 13 14#include "InterfaceUtils.h" 15#include "MessageDriverSettingsUtils.h" 16#include "TextRequestDialog.h" 17 18#include <Box.h> 19#include <MenuField.h> 20#include <MenuItem.h> 21#include <PopUpMenu.h> 22#include <StringView.h> 23 24#include <PPPManager.h> 25#include <PPPoE.h> 26 // from PPPoE addon 27 28 29// GUI constants 30static const uint32 kDefaultButtonWidth = 80; 31 32// message constants 33static const uint32 kMsgSelectInterface = 'SELI'; 34static const uint32 kMsgSelectOther = 'SELO'; 35static const uint32 kMsgFinishSelectOther = 'FISO'; 36static const uint32 kMsgShowServiceWindow = 'SHSW'; 37static const uint32 kMsgChangeService = 'CHGS'; 38static const uint32 kMsgResetService = 'RESS'; 39 40// labels 41static const char *kLabelInterfaceName = "Network Interface: "; 42static const char *kLabelOptional = "(Optional)"; 43static const char *kLabelOtherInterface = "Other:"; 44static const char *kLabelSelectInterface = "Select Interface..."; 45static const char *kLabelServiceName = "Service: "; 46 47// requests 48static const char *kRequestInterfaceName = "Network Interface Name: "; 49 50// add-on descriptions 51static const char *kFriendlyName = "Broadband: DSL, Cable, etc."; 52static const char *kTechnicalName = "PPPoE"; 53static const char *kKernelModuleName = "pppoe"; 54 55 56PPPoEAddon::PPPoEAddon(BMessage *addons) 57 : DialUpAddon(addons), 58 fSettings(NULL), 59 fProfile(NULL), 60 fPPPoEView(NULL) 61{ 62 fHeight = 20 // interface name control 63 + 20 // service control 64 + 5 + 2; // space between controls and bottom 65} 66 67 68PPPoEAddon::~PPPoEAddon() 69{ 70 delete fPPPoEView; 71 // this may have been set to NULL from the view's destructor! 72} 73 74 75const char* 76PPPoEAddon::FriendlyName() const 77{ 78 return kFriendlyName; 79} 80 81 82const char* 83PPPoEAddon::TechnicalName() const 84{ 85 return kTechnicalName; 86} 87 88 89const char* 90PPPoEAddon::KernelModuleName() const 91{ 92 return kKernelModuleName; 93} 94 95 96bool 97PPPoEAddon::LoadSettings(BMessage *settings, BMessage *profile, bool isNew) 98{ 99 fIsNew = isNew; 100 fInterfaceName = fServiceName = ""; 101 fSettings = settings; 102 fProfile = profile; 103 104 if(fPPPoEView) 105 fPPPoEView->Reload(); 106 107 if(!settings || !profile || isNew) 108 return true; 109 110 BMessage device; 111 int32 deviceIndex = 0; 112 if(!FindMessageParameter(PPP_DEVICE_KEY, *fSettings, &device, &deviceIndex)) 113 return false; 114 // error: no device 115 116 BString name; 117 if(device.FindString(MDSU_VALUES, &name) != B_OK || name != kKernelModuleName) 118 return false; 119 // error: no device 120 121 BMessage parameter; 122 int32 index = 0; 123 if(!FindMessageParameter(PPPoE_INTERFACE_KEY, device, ¶meter, &index) 124 || parameter.FindString(MDSU_VALUES, &fInterfaceName) != B_OK) 125 return false; 126 // error: no interface 127 else { 128 parameter.AddBool(MDSU_VALID, true); 129 device.ReplaceMessage(MDSU_PARAMETERS, index, ¶meter); 130 } 131 132 index = 0; 133 if(!FindMessageParameter(PPPoE_SERVICE_NAME_KEY, device, ¶meter, &index) 134 || parameter.FindString(MDSU_VALUES, &fServiceName) != B_OK) 135 fServiceName = ""; 136 else { 137 parameter.AddBool(MDSU_VALID, true); 138 device.ReplaceMessage(MDSU_PARAMETERS, index, ¶meter); 139 } 140 141 device.AddBool(MDSU_VALID, true); 142 fSettings->ReplaceMessage(MDSU_PARAMETERS, deviceIndex, &device); 143 144 if(fPPPoEView) 145 fPPPoEView->Reload(); 146 147 return true; 148} 149 150 151void 152PPPoEAddon::IsModified(bool *settings, bool *profile) const 153{ 154 *profile = false; 155 156 if(!fSettings) { 157 *settings = false; 158 return; 159 } 160 161 *settings = (fInterfaceName != fPPPoEView->InterfaceName() 162 || fServiceName != fPPPoEView->ServiceName()); 163} 164 165 166bool 167PPPoEAddon::SaveSettings(BMessage *settings, BMessage *profile, bool saveTemporary) 168{ 169 if(!fSettings || !settings || !fPPPoEView->InterfaceName() 170 || strlen(fPPPoEView->InterfaceName()) == 0) 171 return false; 172 // TODO: tell user that an interface is needed (if we fail because of this) 173 174 BMessage device, interface; 175 device.AddString(MDSU_NAME, PPP_DEVICE_KEY); 176 device.AddString(MDSU_VALUES, kKernelModuleName); 177 178 interface.AddString(MDSU_NAME, PPPoE_INTERFACE_KEY); 179 interface.AddString(MDSU_VALUES, fPPPoEView->InterfaceName()); 180 device.AddMessage(MDSU_PARAMETERS, &interface); 181 182 if(fPPPoEView->ServiceName() && strlen(fPPPoEView->ServiceName()) > 0) { 183 // save service name, too 184 BMessage service; 185 service.AddString(MDSU_NAME, PPPoE_SERVICE_NAME_KEY); 186 service.AddString(MDSU_VALUES, fPPPoEView->ServiceName()); 187 device.AddMessage(MDSU_PARAMETERS, &service); 188 } 189 190 settings->AddMessage(MDSU_PARAMETERS, &device); 191 192 return true; 193} 194 195 196bool 197PPPoEAddon::GetPreferredSize(float *width, float *height) const 198{ 199 float viewWidth; 200 if(Addons()->FindFloat(DUN_DEVICE_VIEW_WIDTH, &viewWidth) != B_OK) 201 viewWidth = 270; 202 // default value 203 204 if(width) 205 *width = viewWidth; 206 if(height) 207 *height = fHeight; 208 209 return true; 210} 211 212 213BView* 214PPPoEAddon::CreateView() 215{ 216 if(!fPPPoEView) { 217 float width; 218 if(!Addons()->FindFloat(DUN_DEVICE_VIEW_WIDTH, &width)) 219 width = 270; 220 // default value 221 222 BRect rect(0, 0, width, fHeight); 223 fPPPoEView = new PPPoEView(this, rect); 224 fPPPoEView->Reload(); 225 } 226 227 return fPPPoEView; 228} 229 230 231PPPoEView::PPPoEView(PPPoEAddon *addon, BRect frame) 232 : BView(frame, "PPPoEView", B_FOLLOW_NONE, 0), 233 fAddon(addon) 234{ 235 BRect rect = Bounds(); 236 rect.InsetBy(5, 0); 237 rect.bottom = 20; 238 fInterface = new BMenuField(rect, "interface", kLabelInterfaceName, 239 new BPopUpMenu(kLabelSelectInterface)); 240 fInterface->SetDivider(StringWidth(fInterface->Label()) + 5); 241 fInterface->Menu()->AddSeparatorItem(); 242 fOtherInterface = new BMenuItem(kLabelOtherInterface, 243 new BMessage(kMsgSelectOther)); 244 fInterface->Menu()->AddItem(fOtherInterface); 245 rect.top = rect.bottom + 5; 246 rect.bottom = rect.top + 20; 247 rect.right -= 75; 248 fServiceName = new BTextControl(rect, "service", kLabelServiceName, NULL, NULL); 249 fServiceName->SetDivider(StringWidth(fServiceName->Label()) + 5); 250 rect.left = rect.right + 5; 251 rect.right += 75; 252 rect.bottom = rect.top + 15; 253 AddChild(new BStringView(rect, "optional", kLabelOptional)); 254 255 AddChild(fInterface); 256 AddChild(fServiceName); 257} 258 259 260PPPoEView::~PPPoEView() 261{ 262 Addon()->UnregisterView(); 263} 264 265 266void 267PPPoEView::Reload() 268{ 269 ReloadInterfaces(); 270 fServiceName->SetText(Addon()->ServiceName()); 271} 272 273 274void 275PPPoEView::AttachedToWindow() 276{ 277 SetViewColor(Parent()->ViewColor()); 278 fInterface->Menu()->SetTargetForItems(this); 279 fServiceName->SetTarget(this); 280} 281 282 283void 284PPPoEView::MessageReceived(BMessage *message) 285{ 286 switch(message->what) { 287 case kMsgSelectInterface: { 288 BMenuItem *item = fInterface->Menu()->FindMarked(); 289 if(item) 290 fInterfaceName = item->Label(); 291 } break; 292 293 case kMsgSelectOther: 294 (new TextRequestDialog("InterfaceName", NULL, kRequestInterfaceName, 295 fInterfaceName.String()))->Go(new BInvoker( 296 new BMessage(kMsgFinishSelectOther), this)); 297 break; 298 299 case kMsgFinishSelectOther: { 300 int32 which; 301 message->FindInt32("which", &which); 302 303 const char *name = message->FindString("text"); 304 BMenu *menu = fInterface->Menu(); 305 BMenuItem *item; 306 if(which != 1 || !name || strlen(name) == 0) { 307 item = menu->FindItem(fInterfaceName.String()); 308 if(item && menu->IndexOf(item) <= menu->CountItems() - 2) 309 item->SetMarked(true); 310 else 311 fOtherInterface->SetMarked(true); 312 313 return; 314 } 315 316 fInterfaceName = name; 317 318 item = menu->FindItem(fInterfaceName.String()); 319 if(item && menu->IndexOf(item) <= menu->CountItems() - 2) { 320 item->SetMarked(true); 321 return; 322 } 323 324 BString label(kLabelOtherInterface); 325 label << " " << name; 326 fOtherInterface->SetLabel(label.String()); 327 fOtherInterface->SetMarked(true); 328 // XXX: this is needed to tell the owning menu to update its label 329 } break; 330 331 default: 332 BView::MessageReceived(message); 333 } 334} 335 336 337void 338PPPoEView::ReloadInterfaces() 339{ 340 // delete all items and request a new bunch from the pppoe kernel module 341 BMenu *menu = fInterface->Menu(); 342 while(menu->CountItems() > 2) 343 delete menu->RemoveItem((int32) 0); 344 fOtherInterface->SetLabel(kLabelOtherInterface); 345 346 PPPManager manager; 347 char *interfaces = new char[8192]; 348 // reserve enough space for approximately 512 entries 349 int32 count = manager.ControlModule("pppoe", PPPoE_GET_INTERFACES, interfaces, 350 8192); 351 352 BMenuItem *item; 353 char *name = interfaces; 354 int32 insertAt; 355 for(int32 index = 0; index < count; index++) { 356 item = new BMenuItem(name, new BMessage(kMsgSelectInterface)); 357 insertAt = FindNextMenuInsertionIndex(menu, name); 358 if(insertAt > menu->CountItems() - 2) 359 insertAt = menu->CountItems() - 2; 360 361 item->SetTarget(this); 362 menu->AddItem(item, insertAt); 363 name += strlen(name) + 1; 364 } 365 366 // set interface or some default value if nothing was found 367 if(Addon()->InterfaceName() && strlen(Addon()->InterfaceName()) > 0) 368 fInterfaceName = Addon()->InterfaceName(); 369 else if(count > 0) 370 fInterfaceName = interfaces; 371 else 372 fInterfaceName = ""; 373 374 delete interfaces; 375 376 item = menu->FindItem(fInterfaceName.String()); 377 if(item && menu->IndexOf(item) <= menu->CountItems() - 2) 378 item->SetMarked(true); 379 else if(Addon()->InterfaceName()) { 380 BString label(kLabelOtherInterface); 381 label << " " << fInterfaceName; 382 fOtherInterface->SetLabel(label.String()); 383 fOtherInterface->SetMarked(true); 384 } 385} 386