* Copyright 2003-2004 Waldemar Kornewald. All rights reserved.
* Copyright 2017 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "PPPoEAddon.h"
#include "InterfaceUtils.h"
#include "MessageDriverSettingsUtils.h"
#include "TextRequestDialog.h"
#include <Box.h>
#include <MenuField.h>
#include <MenuItem.h>
#include <PopUpMenu.h>
#include <StringView.h>
#include <PPPManager.h>
#include <PPPoE.h>
static const uint32 kDefaultButtonWidth = 80;
static const uint32 kMsgSelectInterface = 'SELI';
static const uint32 kMsgSelectOther = 'SELO';
static const uint32 kMsgFinishSelectOther = 'FISO';
static const uint32 kMsgShowServiceWindow = 'SHSW';
static const uint32 kMsgChangeService = 'CHGS';
static const uint32 kMsgResetService = 'RESS';
static const char *kLabelInterfaceName = "Network Interface: ";
static const char *kLabelOptional = "(Optional)";
static const char *kLabelOtherInterface = "Other:";
static const char *kLabelSelectInterface = "Select Interface...";
static const char *kLabelServiceName = "Service: ";
static const char *kRequestInterfaceName = "Network Interface Name: ";
static const char *kFriendlyName = "Broadband: DSL, Cable, etc.";
static const char *kTechnicalName = "PPPoE";
static const char *kKernelModuleName = "pppoe";
PPPoEAddon::PPPoEAddon(BMessage *addons)
: DialUpAddon(addons),
fSettings(NULL),
fProfile(NULL),
fPPPoEView(NULL)
{
fHeight = 20
+ 20
+ 5 + 2;
}
PPPoEAddon::~PPPoEAddon()
{
delete fPPPoEView;
}
const char*
PPPoEAddon::FriendlyName() const
{
return kFriendlyName;
}
const char*
PPPoEAddon::TechnicalName() const
{
return kTechnicalName;
}
const char*
PPPoEAddon::KernelModuleName() const
{
return kKernelModuleName;
}
bool
PPPoEAddon::LoadSettings(BMessage *settings, BMessage *profile, bool isNew)
{
fIsNew = isNew;
fInterfaceName = fServiceName = "";
fSettings = settings;
fProfile = profile;
if(fPPPoEView)
fPPPoEView->Reload();
if(!settings || !profile || isNew)
return true;
BMessage device;
int32 deviceIndex = 0;
if(!FindMessageParameter(PPP_DEVICE_KEY, *fSettings, &device, &deviceIndex))
return false;
BString name;
if(device.FindString(MDSU_VALUES, &name) != B_OK || name != kKernelModuleName)
return false;
BMessage parameter;
int32 index = 0;
if(!FindMessageParameter(PPPoE_INTERFACE_KEY, device, ¶meter, &index)
|| parameter.FindString(MDSU_VALUES, &fInterfaceName) != B_OK)
return false;
else {
parameter.AddBool(MDSU_VALID, true);
device.ReplaceMessage(MDSU_PARAMETERS, index, ¶meter);
}
index = 0;
if(!FindMessageParameter(PPPoE_SERVICE_NAME_KEY, device, ¶meter, &index)
|| parameter.FindString(MDSU_VALUES, &fServiceName) != B_OK)
fServiceName = "";
else {
parameter.AddBool(MDSU_VALID, true);
device.ReplaceMessage(MDSU_PARAMETERS, index, ¶meter);
}
device.AddBool(MDSU_VALID, true);
fSettings->ReplaceMessage(MDSU_PARAMETERS, deviceIndex, &device);
if(fPPPoEView)
fPPPoEView->Reload();
return true;
}
void
PPPoEAddon::IsModified(bool *settings, bool *profile) const
{
*profile = false;
if(!fSettings) {
*settings = false;
return;
}
*settings = (fInterfaceName != fPPPoEView->InterfaceName()
|| fServiceName != fPPPoEView->ServiceName());
}
bool
PPPoEAddon::SaveSettings(BMessage *settings, BMessage *profile, bool saveTemporary)
{
if(!fSettings || !settings || !fPPPoEView->InterfaceName()
|| strlen(fPPPoEView->InterfaceName()) == 0)
return false;
BMessage device, interface;
device.AddString(MDSU_NAME, PPP_DEVICE_KEY);
device.AddString(MDSU_VALUES, kKernelModuleName);
interface.AddString(MDSU_NAME, PPPoE_INTERFACE_KEY);
interface.AddString(MDSU_VALUES, fPPPoEView->InterfaceName());
device.AddMessage(MDSU_PARAMETERS, &interface);
if(fPPPoEView->ServiceName() && strlen(fPPPoEView->ServiceName()) > 0) {
BMessage service;
service.AddString(MDSU_NAME, PPPoE_SERVICE_NAME_KEY);
service.AddString(MDSU_VALUES, fPPPoEView->ServiceName());
device.AddMessage(MDSU_PARAMETERS, &service);
}
settings->AddMessage(MDSU_PARAMETERS, &device);
return true;
}
bool
PPPoEAddon::GetPreferredSize(float *width, float *height) const
{
float viewWidth;
if(Addons()->FindFloat(DUN_DEVICE_VIEW_WIDTH, &viewWidth) != B_OK)
viewWidth = 270;
if(width)
*width = viewWidth;
if(height)
*height = fHeight;
return true;
}
BView*
PPPoEAddon::CreateView()
{
if(!fPPPoEView) {
float width;
if(!Addons()->FindFloat(DUN_DEVICE_VIEW_WIDTH, &width))
width = 270;
BRect rect(0, 0, width, fHeight);
fPPPoEView = new PPPoEView(this, rect);
fPPPoEView->Reload();
}
return fPPPoEView;
}
PPPoEView::PPPoEView(PPPoEAddon *addon, BRect frame)
: BView(frame, "PPPoEView", B_FOLLOW_NONE, 0),
fAddon(addon)
{
BRect rect = Bounds();
rect.InsetBy(5, 0);
rect.bottom = 20;
fInterface = new BMenuField(rect, "interface", kLabelInterfaceName,
new BPopUpMenu(kLabelSelectInterface));
fInterface->SetDivider(StringWidth(fInterface->Label()) + 5);
fInterface->Menu()->AddSeparatorItem();
fOtherInterface = new BMenuItem(kLabelOtherInterface,
new BMessage(kMsgSelectOther));
fInterface->Menu()->AddItem(fOtherInterface);
rect.top = rect.bottom + 5;
rect.bottom = rect.top + 20;
rect.right -= 75;
fServiceName = new BTextControl(rect, "service", kLabelServiceName, NULL, NULL);
fServiceName->SetDivider(StringWidth(fServiceName->Label()) + 5);
rect.left = rect.right + 5;
rect.right += 75;
rect.bottom = rect.top + 15;
AddChild(new BStringView(rect, "optional", kLabelOptional));
AddChild(fInterface);
AddChild(fServiceName);
}
PPPoEView::~PPPoEView()
{
Addon()->UnregisterView();
}
void
PPPoEView::Reload()
{
ReloadInterfaces();
fServiceName->SetText(Addon()->ServiceName());
}
void
PPPoEView::AttachedToWindow()
{
SetViewColor(Parent()->ViewColor());
fInterface->Menu()->SetTargetForItems(this);
fServiceName->SetTarget(this);
}
void
PPPoEView::MessageReceived(BMessage *message)
{
switch(message->what) {
case kMsgSelectInterface: {
BMenuItem *item = fInterface->Menu()->FindMarked();
if(item)
fInterfaceName = item->Label();
} break;
case kMsgSelectOther:
(new TextRequestDialog("InterfaceName", NULL, kRequestInterfaceName,
fInterfaceName.String()))->Go(new BInvoker(
new BMessage(kMsgFinishSelectOther), this));
break;
case kMsgFinishSelectOther: {
int32 which;
message->FindInt32("which", &which);
const char *name = message->FindString("text");
BMenu *menu = fInterface->Menu();
BMenuItem *item;
if(which != 1 || !name || strlen(name) == 0) {
item = menu->FindItem(fInterfaceName.String());
if(item && menu->IndexOf(item) <= menu->CountItems() - 2)
item->SetMarked(true);
else
fOtherInterface->SetMarked(true);
return;
}
fInterfaceName = name;
item = menu->FindItem(fInterfaceName.String());
if(item && menu->IndexOf(item) <= menu->CountItems() - 2) {
item->SetMarked(true);
return;
}
BString label(kLabelOtherInterface);
label << " " << name;
fOtherInterface->SetLabel(label.String());
fOtherInterface->SetMarked(true);
} break;
default:
BView::MessageReceived(message);
}
}
void
PPPoEView::ReloadInterfaces()
{
BMenu *menu = fInterface->Menu();
while(menu->CountItems() > 2)
delete menu->RemoveItem((int32) 0);
fOtherInterface->SetLabel(kLabelOtherInterface);
PPPManager manager;
char *interfaces = new char[8192];
int32 count = manager.ControlModule("pppoe", PPPoE_GET_INTERFACES, interfaces,
8192);
BMenuItem *item;
char *name = interfaces;
int32 insertAt;
for(int32 index = 0; index < count; index++) {
item = new BMenuItem(name, new BMessage(kMsgSelectInterface));
insertAt = FindNextMenuInsertionIndex(menu, name);
if(insertAt > menu->CountItems() - 2)
insertAt = menu->CountItems() - 2;
item->SetTarget(this);
menu->AddItem(item, insertAt);
name += strlen(name) + 1;
}
if(Addon()->InterfaceName() && strlen(Addon()->InterfaceName()) > 0)
fInterfaceName = Addon()->InterfaceName();
else if(count > 0)
fInterfaceName = interfaces;
else
fInterfaceName = "";
delete interfaces;
item = menu->FindItem(fInterfaceName.String());
if(item && menu->IndexOf(item) <= menu->CountItems() - 2)
item->SetMarked(true);
else if(Addon()->InterfaceName()) {
BString label(kLabelOtherInterface);
label << " " << fInterfaceName;
fOtherInterface->SetLabel(label.String());
fOtherInterface->SetMarked(true);
}
}