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 // GeneralAddon saves the loaded settings. 9 // GeneralView saves the current settings. 10 //----------------------------------------------------------------------- 11 12 #include "GeneralAddon.h" 13 14 #include "InterfaceUtils.h" 15 #include "MessageDriverSettingsUtils.h" 16 17 #include <Box.h> 18 #include <Button.h> 19 #include <MenuField.h> 20 #include <MenuItem.h> 21 #include <LayoutBuilder.h> 22 #include <PopUpMenu.h> 23 #include <StringView.h> 24 25 #include <PPPDefs.h> 26 27 28 // message constants 29 static const uint32 kMsgSelectDevice = 'SELD'; 30 static const uint32 kMsgSelectAuthenticator = 'SELA'; 31 32 // labels 33 static const char *kLabelGeneral = "General"; 34 static const char *kLabelDevice = "Device: "; 35 static const char *kLabelNoDevicesFound = "No Devices Found!"; 36 static const char *kLabelAuthenticator = "Login: "; 37 static const char *kLabelNoAuthenticatorsFound = "No Authenticators Found!"; 38 static const char *kLabelName = "Username: "; 39 static const char *kLabelPassword = "Password: "; 40 static const char *kLabelSavePassword = "Save Password"; 41 static const char *kLabelNone = "None"; 42 43 // string constants for information saved in the settings message 44 static const char *kGeneralTabAuthentication = "Authentication"; 45 static const char *kGeneralTabAuthenticators = "Authenticators"; 46 47 48 #define DEFAULT_AUTHENTICATOR "PAP" 49 // this authenticator is selected by default when creating a new interface 50 51 52 GeneralAddon::GeneralAddon(BMessage *addons) 53 : DialUpAddon(addons), 54 fHasPassword(false), 55 fAuthenticatorsCount(0), 56 fSettings(NULL), 57 fProfile(NULL), 58 fGeneralView(NULL) 59 { 60 } 61 62 63 GeneralAddon::~GeneralAddon() 64 { 65 } 66 67 68 bool 69 GeneralAddon::NeedsAuthenticationRequest() const 70 { 71 return fGeneralView->AuthenticatorName(); 72 } 73 74 75 DialUpAddon* 76 GeneralAddon::FindDevice(const BString& moduleName) const 77 { 78 DialUpAddon *addon; 79 for(int32 index = 0; Addons()->FindPointer(DUN_DEVICE_ADDON_TYPE, index, 80 reinterpret_cast<void**>(&addon)) == B_OK; index++) 81 if(addon && moduleName == addon->KernelModuleName()) 82 return addon; 83 84 return NULL; 85 } 86 87 88 bool 89 GeneralAddon::LoadSettings(BMessage *settings, BMessage *profile, bool isNew) 90 { 91 fIsNew = isNew; 92 fHasPassword = false; 93 fDeviceName = fUsername = fPassword = ""; 94 fDeviceAddon = NULL; 95 fAuthenticatorsCount = 0; 96 fSettings = settings; 97 fProfile = profile; 98 99 if(fGeneralView) 100 fGeneralView->Reload(); 101 // reset all views (empty settings) 102 103 if(!settings || !profile || isNew) 104 return true; 105 106 if(!LoadDeviceSettings()) 107 return false; 108 109 if(!LoadAuthenticationSettings()) 110 return false; 111 112 if(fGeneralView) 113 fGeneralView->Reload(); 114 // reload new settings 115 116 return true; 117 } 118 119 120 bool 121 GeneralAddon::LoadDeviceSettings() 122 { 123 int32 index = 0; 124 BMessage device; 125 if(!FindMessageParameter(PPP_DEVICE_KEY, *fSettings, &device, &index)) 126 return false; 127 // TODO: tell user that device specification is missing 128 129 if(device.FindString(MDSU_VALUES, &fDeviceName) != B_OK) 130 return false; 131 // TODO: tell user that device specification is missing 132 133 device.AddBool(MDSU_VALID, true); 134 fSettings->ReplaceMessage(MDSU_PARAMETERS, index, &device); 135 136 fDeviceAddon = FindDevice(fDeviceName); 137 if(!fDeviceAddon) 138 return false; 139 140 return fDeviceAddon->LoadSettings(fSettings, fProfile, false); 141 } 142 143 144 bool 145 GeneralAddon::LoadAuthenticationSettings() 146 { 147 // we only handle the profile (although settings could contain different data) 148 int32 itemIndex = 0; 149 BMessage authentication, item; 150 151 if(!FindMessageParameter(PPP_AUTHENTICATOR_KEY, *fProfile, &item, &itemIndex)) 152 return true; 153 154 // find authenticators (though we load all authenticators, we only use one) 155 BString name; 156 for(int32 index = 0; item.FindString(MDSU_VALUES, index, &name) == B_OK; index++) { 157 BMessage authenticator; 158 if(!GetAuthenticator(name, &authenticator)) 159 return false; 160 // fatal error: we do not know how to handle this authenticator 161 162 MarkAuthenticatorAsValid(name); 163 authentication.AddString(kGeneralTabAuthenticators, name); 164 ++fAuthenticatorsCount; 165 } 166 167 fSettings->AddMessage(kGeneralTabAuthentication, &authentication); 168 169 bool hasUsername = false; 170 // a username must be present 171 172 // load username and password 173 BMessage parameter; 174 int32 parameterIndex = 0; 175 if(FindMessageParameter("User", item, ¶meter, ¶meterIndex) 176 && parameter.FindString(MDSU_VALUES, &fUsername) == B_OK) { 177 hasUsername = true; 178 parameter.AddBool(MDSU_VALID, true); 179 item.ReplaceMessage(MDSU_PARAMETERS, parameterIndex, ¶meter); 180 } 181 182 parameterIndex = 0; 183 if(FindMessageParameter("Password", item, ¶meter, ¶meterIndex) 184 && parameter.FindString(MDSU_VALUES, &fPassword) == B_OK) { 185 fHasPassword = true; 186 parameter.AddBool(MDSU_VALID, true); 187 item.ReplaceMessage(MDSU_PARAMETERS, parameterIndex, ¶meter); 188 } 189 190 // tell DUN whether everything is valid 191 if(hasUsername) 192 item.AddBool(MDSU_VALID, true); 193 194 fProfile->ReplaceMessage(MDSU_PARAMETERS, itemIndex, &item); 195 196 return true; 197 } 198 199 200 bool 201 GeneralAddon::HasTemporaryProfile() const 202 { 203 return fGeneralView->HasTemporaryProfile(); 204 } 205 206 207 void 208 GeneralAddon::IsModified(bool *settings, bool *profile) const 209 { 210 if(!fSettings) { 211 *settings = *profile = false; 212 return; 213 } 214 215 bool deviceSettings, authenticationSettings, deviceProfile, authenticationProfile; 216 217 IsDeviceModified(&deviceSettings, &deviceProfile); 218 IsAuthenticationModified(&authenticationSettings, &authenticationProfile); 219 220 *settings = (deviceSettings || authenticationSettings); 221 *profile = (deviceProfile || authenticationProfile); 222 } 223 224 225 void 226 GeneralAddon::IsDeviceModified(bool *settings, bool *profile) const 227 { 228 fGeneralView->IsDeviceModified(settings, profile); 229 } 230 231 232 void 233 GeneralAddon::IsAuthenticationModified(bool *settings, bool *profile) const 234 { 235 // currently we only support selecting one authenticator 236 if(fAuthenticatorsCount == 0) 237 *settings = fGeneralView->AuthenticatorName(); 238 else { 239 BMessage authentication; 240 if(fSettings->FindMessage(kGeneralTabAuthentication, &authentication) != B_OK) { 241 *settings = *profile = false; 242 return; 243 // error! 244 } 245 246 BString authenticator; 247 if(authentication.FindString(kGeneralTabAuthenticators, 248 &authenticator) != B_OK) { 249 *settings = *profile = false; 250 return; 251 // error! 252 } 253 254 *settings = (!fGeneralView->AuthenticatorName() 255 || authenticator != fGeneralView->AuthenticatorName()); 256 } 257 258 *profile = (*settings || fUsername != fGeneralView->Username() 259 || (fPassword != fGeneralView->Password() && fHasPassword) 260 || fHasPassword != fGeneralView->DoesSavePassword()); 261 } 262 263 264 bool 265 GeneralAddon::SaveSettings(BMessage *settings, BMessage *profile, bool saveTemporary) 266 { 267 if(!fSettings || !settings || !fGeneralView->DeviceName()) 268 return false; 269 // TODO: tell user that a device is needed (if we fail because of this) 270 271 if(!fGeneralView->DeviceAddon() || !fGeneralView->DeviceAddon()->SaveSettings( 272 settings, profile, saveTemporary)) 273 return false; 274 275 if(fGeneralView->AuthenticatorName()) { 276 BMessage authenticator; 277 authenticator.AddString(MDSU_NAME, PPP_AUTHENTICATOR_KEY); 278 authenticator.AddString(MDSU_VALUES, fGeneralView->AuthenticatorName()); 279 settings->AddMessage(MDSU_PARAMETERS, &authenticator); 280 281 BMessage username; 282 username.AddString(MDSU_NAME, "User"); 283 username.AddString(MDSU_VALUES, fGeneralView->Username()); 284 authenticator.AddMessage(MDSU_PARAMETERS, &username); 285 286 if(saveTemporary || fGeneralView->DoesSavePassword()) { 287 // save password, too 288 BMessage password; 289 password.AddString(MDSU_NAME, "Password"); 290 password.AddString(MDSU_VALUES, fGeneralView->Password()); 291 authenticator.AddMessage(MDSU_PARAMETERS, &password); 292 } 293 294 profile->AddMessage(MDSU_PARAMETERS, &authenticator); 295 } 296 297 return true; 298 } 299 300 301 bool 302 GeneralAddon::GetPreferredSize(float *width, float *height) const 303 { 304 BRect rect; 305 if(Addons()->FindRect(DUN_TAB_VIEW_RECT, &rect) != B_OK) 306 rect.Set(0, 0, 200, 300); 307 // set default values 308 309 if(width) 310 *width = rect.Width(); 311 if(height) 312 *height = rect.Height(); 313 314 return true; 315 } 316 317 318 BView* 319 GeneralAddon::CreateView() 320 { 321 if (!fGeneralView) { 322 fGeneralView = new GeneralView(this); 323 fGeneralView->Reload(); 324 } 325 326 return fGeneralView; 327 } 328 329 330 bool 331 GeneralAddon::GetAuthenticator(const BString& moduleName, BMessage *entry) const 332 { 333 if(!entry) 334 return false; 335 336 BString name; 337 for(int32 index = 0; Addons()->FindMessage(DUN_AUTHENTICATOR_ADDON_TYPE, index, 338 entry) == B_OK; index++) { 339 entry->FindString("KernelModuleName", &name); 340 if (name == moduleName) 341 return true; 342 } 343 344 return false; 345 } 346 347 348 bool 349 GeneralAddon::MarkAuthenticatorAsValid(const BString& moduleName) 350 { 351 BMessage authenticator; 352 int32 index = 0; 353 BString name; 354 355 for(; FindMessageParameter(PPP_AUTHENTICATOR_KEY, *fSettings, &authenticator, 356 &index); index++) { 357 authenticator.FindString("KernelModuleName", &name); 358 if(name == moduleName) { 359 authenticator.AddBool(MDSU_VALID, true); 360 fSettings->ReplaceMessage(MDSU_PARAMETERS, index, &authenticator); 361 return true; 362 } 363 } 364 365 return false; 366 } 367 368 369 GeneralView::GeneralView(GeneralAddon *addon) 370 : BView(kLabelGeneral, 0), 371 fAddon(addon) 372 { 373 fDeviceBox = new BBox("Device"); 374 Addon()->Addons()->AddFloat(DUN_DEVICE_VIEW_WIDTH, 375 fDeviceBox->Bounds().Width() - 10); // FIXME: remove 376 377 fDeviceField = new BMenuField("Device", 378 kLabelDevice, new BPopUpMenu(kLabelNoDevicesFound)); 379 fDeviceField->Menu()->SetRadioMode(true); 380 AddDevices(); 381 fDeviceBox->SetLabel(fDeviceField); 382 383 fAuthenticatorField = new BMenuField("Authenticator", 384 kLabelAuthenticator, new BPopUpMenu(kLabelNoAuthenticatorsFound)); 385 fAuthenticatorField->Menu()->SetRadioMode(true); 386 AddAuthenticators(); 387 388 fUsername = new BTextControl("username", kLabelName, NULL, NULL); 389 fPassword = new BTextControl("password", kLabelPassword, NULL, NULL); 390 fPassword->TextView()->HideTyping(true); 391 392 fSavePassword = new BCheckBox("SavePassword", kLabelSavePassword, NULL); 393 394 BLayoutBuilder::Group<>(this, B_VERTICAL, B_USE_HALF_ITEM_SPACING) 395 .SetInsets(B_USE_HALF_ITEM_INSETS) 396 .AddGroup(B_HORIZONTAL) 397 .Add(fDeviceBox) 398 .AddGlue() 399 .End() 400 .Add(fAuthenticatorField) 401 .Add(fUsername) 402 .Add(fPassword) 403 .Add(fSavePassword) 404 .AddGlue() 405 .End(); 406 } 407 408 409 GeneralView::~GeneralView() 410 { 411 } 412 413 414 void 415 GeneralView::Reload() 416 { 417 fDeviceAddon = NULL; 418 419 BMenuItem *item = NULL; 420 for(int32 index = 0; index < fDeviceField->Menu()->CountItems(); index++) { 421 item = fDeviceField->Menu()->ItemAt(index); 422 if(item && item->Message() && item->Message()->FindPointer("Addon", 423 reinterpret_cast<void**>(&fDeviceAddon)) == B_OK 424 && fDeviceAddon == Addon()->DeviceAddon()) 425 break; 426 } 427 428 if(fDeviceAddon && fDeviceAddon == Addon()->DeviceAddon()) 429 item->SetMarked(true); 430 else if(Addon()->IsNew() && fDeviceField->Menu()->CountItems() > 0) { 431 item = fDeviceField->Menu()->ItemAt(0); 432 item->SetMarked(true); 433 item->Message()->FindPointer("Addon", reinterpret_cast<void**>(&fDeviceAddon)); 434 fDeviceAddon->LoadSettings(Addon()->Settings(), Addon()->Profile(), true); 435 } else { 436 fDeviceAddon = NULL; 437 item = fDeviceField->Menu()->FindMarked(); 438 if(item) 439 item->SetMarked(false); 440 } 441 442 if(Addon()->CountAuthenticators() > 0) { 443 BString kernelModule, authenticator; 444 BMessage authentication; 445 if(Addon()->Settings()->FindMessage(kGeneralTabAuthentication, 446 &authentication) == B_OK) 447 authentication.FindString(kGeneralTabAuthenticators, &authenticator); 448 BMenu *menu = fAuthenticatorField->Menu(); 449 for(int32 index = 0; index < menu->CountItems(); index++) { 450 item = menu->ItemAt(index); 451 if(item && item->Message() 452 && item->Message()->FindString("KernelModuleName", 453 &kernelModule) == B_OK && kernelModule == authenticator) { 454 item->SetMarked(true); 455 break; 456 } 457 } 458 } else if(Addon()->IsNew() && fAuthenticatorDefault) 459 fAuthenticatorDefault->SetMarked(true); 460 else 461 fAuthenticatorNone->SetMarked(true); 462 463 fUsername->SetText(Addon()->Username()); 464 fPassword->SetText(Addon()->Password()); 465 fSavePassword->SetValue(Addon()->HasPassword()); 466 467 ReloadDeviceView(); 468 UpdateControls(); 469 } 470 471 472 const char* 473 GeneralView::DeviceName() const 474 { 475 if(fDeviceAddon) 476 return fDeviceAddon->KernelModuleName(); 477 478 return NULL; 479 } 480 481 482 const char* 483 GeneralView::AuthenticatorName() const 484 { 485 BMenuItem *marked = fAuthenticatorField->Menu()->FindMarked(); 486 if(marked && marked != fAuthenticatorNone) 487 return marked->Message()->FindString("KernelModuleName"); 488 489 return NULL; 490 } 491 492 493 void 494 GeneralView::IsDeviceModified(bool *settings, bool *profile) const 495 { 496 if(fDeviceAddon != Addon()->DeviceAddon()) 497 *settings = *profile = true; 498 else if(fDeviceAddon) 499 fDeviceAddon->IsModified(settings, profile); 500 else 501 *settings = *profile = false; 502 } 503 504 505 void 506 GeneralView::AttachedToWindow() 507 { 508 SetViewColor(Parent()->ViewColor()); 509 fDeviceField->Menu()->SetTargetForItems(this); 510 fAuthenticatorField->Menu()->SetTargetForItems(this); 511 fUsername->SetTarget(this); 512 fPassword->SetTarget(this); 513 } 514 515 516 void 517 GeneralView::MessageReceived(BMessage *message) 518 { 519 switch(message->what) { 520 case kMsgSelectDevice: 521 if(message->FindPointer("Addon", reinterpret_cast<void**>(&fDeviceAddon)) 522 != B_OK) 523 fDeviceAddon = NULL; 524 else { 525 if(fDeviceAddon != Addon()->DeviceAddon()) 526 fDeviceAddon->LoadSettings(Addon()->Settings(), Addon()->Profile(), 527 Addon()->IsNew()); 528 529 ReloadDeviceView(); 530 } 531 break; 532 533 case kMsgSelectAuthenticator: 534 UpdateControls(); 535 break; 536 537 default: 538 BView::MessageReceived(message); 539 } 540 } 541 542 543 void 544 GeneralView::ReloadDeviceView() 545 { 546 // first remove existing device view(s) 547 while (fDeviceBox->CountChildren() > 1) 548 fDeviceBox->RemoveChild(fDeviceBox->ChildAt(1)); 549 550 if (!fDeviceAddon) 551 return; 552 553 BView* deviceView = fDeviceAddon->CreateView(); 554 if (deviceView) { 555 BLayoutBuilder::Group<>(fDeviceBox, B_VERTICAL) 556 .Add(deviceView) 557 .End(); 558 } 559 } 560 561 562 void 563 GeneralView::UpdateControls() 564 { 565 BMenu *menu = fAuthenticatorField->Menu(); 566 int32 index = menu->IndexOf(menu->FindMarked()); 567 if (index < 0) 568 fAuthenticatorNone->SetMarked(true); 569 570 if (index == 0) { 571 fUsername->SetEnabled(false); 572 fPassword->SetEnabled(false); 573 fSavePassword->SetEnabled(false); 574 } else { 575 fUsername->SetEnabled(true); 576 fPassword->SetEnabled(true); 577 fSavePassword->SetEnabled(true); 578 } 579 } 580 581 582 void 583 GeneralView::AddDevices() 584 { 585 AddAddonsToMenu(Addon()->Addons(), fDeviceField->Menu(), DUN_DEVICE_ADDON_TYPE, 586 kMsgSelectDevice); 587 } 588 589 590 void 591 GeneralView::AddAuthenticators() 592 { 593 fAuthenticatorDefault = NULL; 594 fAuthenticatorNone = new BMenuItem(kLabelNone, 595 new BMessage(kMsgSelectAuthenticator)); 596 fAuthenticatorField->Menu()->AddItem(fAuthenticatorNone); 597 fAuthenticatorNone->SetMarked(true); 598 fAuthenticatorField->Menu()->AddSeparatorItem(); 599 600 BMenuItem *item; 601 BMessage addon; 602 for(int32 index = 0; 603 Addon()->Addons()->FindMessage(DUN_AUTHENTICATOR_ADDON_TYPE, index, 604 &addon) == B_OK; index++) { 605 BMessage *message = new BMessage(kMsgSelectAuthenticator); 606 message->AddString("KernelModuleName", addon.FindString("KernelModuleName")); 607 608 BString name, technicalName, friendlyName; 609 bool hasTechnicalName 610 = (addon.FindString("TechnicalName", &technicalName) == B_OK); 611 bool hasFriendlyName 612 = (addon.FindString("FriendlyName", &friendlyName) == B_OK); 613 if(hasTechnicalName) { 614 name << technicalName; 615 if(hasFriendlyName) 616 name << " ("; 617 } 618 if(hasFriendlyName) { 619 name << friendlyName; 620 if(hasTechnicalName) 621 name << ")"; 622 } 623 624 int32 insertAt = FindNextMenuInsertionIndex(fAuthenticatorField->Menu(), 625 name.String(), 2); 626 item = new BMenuItem(name.String(), message); 627 if(hasTechnicalName && technicalName == DEFAULT_AUTHENTICATOR) 628 fAuthenticatorDefault = item; 629 fAuthenticatorField->Menu()->AddItem(item, insertAt); 630 } 631 } 632