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 30 static const uint32 kDefaultButtonWidth = 80; 31 32 // message constants 33 static const uint32 kMsgSelectInterface = 'SELI'; 34 static const uint32 kMsgSelectOther = 'SELO'; 35 static const uint32 kMsgFinishSelectOther = 'FISO'; 36 static const uint32 kMsgShowServiceWindow = 'SHSW'; 37 static const uint32 kMsgChangeService = 'CHGS'; 38 static const uint32 kMsgResetService = 'RESS'; 39 40 // labels 41 static const char *kLabelInterfaceName = "Network Interface: "; 42 static const char *kLabelOptional = "(Optional)"; 43 static const char *kLabelOtherInterface = "Other:"; 44 static const char *kLabelSelectInterface = "Select Interface..."; 45 static const char *kLabelServiceName = "Service: "; 46 47 // requests 48 static const char *kRequestInterfaceName = "Network Interface Name: "; 49 50 // add-on descriptions 51 static const char *kFriendlyName = "Broadband: DSL, Cable, etc."; 52 static const char *kTechnicalName = "PPPoE"; 53 static const char *kKernelModuleName = "pppoe"; 54 55 56 PPPoEAddon::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 68 PPPoEAddon::~PPPoEAddon() 69 { 70 delete fPPPoEView; 71 // this may have been set to NULL from the view's destructor! 72 } 73 74 75 const char* 76 PPPoEAddon::FriendlyName() const 77 { 78 return kFriendlyName; 79 } 80 81 82 const char* 83 PPPoEAddon::TechnicalName() const 84 { 85 return kTechnicalName; 86 } 87 88 89 const char* 90 PPPoEAddon::KernelModuleName() const 91 { 92 return kKernelModuleName; 93 } 94 95 96 bool 97 PPPoEAddon::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 151 void 152 PPPoEAddon::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 166 bool 167 PPPoEAddon::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 196 bool 197 PPPoEAddon::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 213 BView* 214 PPPoEAddon::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 231 PPPoEView::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 260 PPPoEView::~PPPoEView() 261 { 262 Addon()->UnregisterView(); 263 } 264 265 266 void 267 PPPoEView::Reload() 268 { 269 ReloadInterfaces(); 270 fServiceName->SetText(Addon()->ServiceName()); 271 } 272 273 274 void 275 PPPoEView::AttachedToWindow() 276 { 277 SetViewColor(Parent()->ViewColor()); 278 fInterface->Menu()->SetTargetForItems(this); 279 fServiceName->SetTarget(this); 280 } 281 282 283 void 284 PPPoEView::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 337 void 338 PPPoEView::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