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.
8 #include "DialUpView.h"
9 #include "DialUpAddon.h"
12 #include "InterfaceUtils.h"
13 #include "MessageDriverSettingsUtils.h"
14 #include "TextRequestDialog.h"
17 #include "ConnectionOptionsAddon.h"
18 #include "GeneralAddon.h"
19 #include "IPCPAddon.h"
20 #include "PPPoEAddon.h"
22 #include <PPPInterface.h>
23 #include <settings_tools.h>
24 #include <TemplateList.h>
26 #include <Application.h>
30 #include <MenuField.h>
32 #include <Messenger.h>
33 #include <PopUpMenu.h>
34 #include <LayoutBuilder.h>
35 #include <StringView.h>
38 #include <Directory.h>
45 static const uint32 kMsgCreateNew
= 'NEWI';
46 static const uint32 kMsgFinishCreateNew
= 'FNEW';
47 static const uint32 kMsgDeleteCurrent
= 'DELI';
48 static const uint32 kMsgSelectInterface
= 'SELI';
49 static const uint32 kMsgConnectButton
= 'CONI';
52 static const char *kLabelInterface
= "Interface: ";
53 static const char *kLabelInterfaceName
= "Interface Name: ";
54 static const char *kLabelCreateNewInterface
= "Create New Interface";
55 static const char *kLabelCreateNew
= "Create New...";
56 static const char *kLabelDeleteCurrent
= "Delete Current";
57 static const char *kLabelConnect
= "Connect";
58 static const char *kLabelDisconnect
= "Disconnect";
59 static const char *kLabelOK
= "OK";
61 // connection status strings
62 static const char *kTextConnecting
= "Connecting...";
63 static const char *kTextConnectionEstablished
= "Connection established.";
64 static const char *kTextNotConnected
= "Not connected.";
65 static const char *kTextDeviceUpFailed
= "Failed to connect.";
66 static const char *kTextAuthenticating
= "Authenticating...";
67 static const char *kTextAuthenticationFailed
= "Authentication failed!";
68 static const char *kTextConnectionLost
= "Connection lost!";
69 static const char *kTextCreationError
= "Error creating interface!";
70 static const char *kTextNoInterfacesFound
= "Please create a new interface...";
71 static const char *kTextChooseInterfaceName
= "Please choose a new name for this "
74 // error strings for alerts
75 static const char *kErrorTitle
= "Error";
76 static const char *kErrorNoPPPStack
= "Error: Could not access the PPP stack!";
77 static const char *kErrorInterfaceExists
= "Error: An interface with this name "
79 static const char *kErrorLoadingFailed
= "Error: Failed loading interface! The "
80 "current settings will be deleted.";
81 static const char *kErrorSavingFailed
= "Error: Failed saving interface settings!";
86 up_down_thread(void *data
)
88 static_cast<DialUpView
*>(data
)->UpDownThread();
93 DialUpView::DialUpView()
94 : BView("DialUpView", 0),
97 fDriverSettings(NULL
),
99 fWatching(PPP_UNDEFINED_INTERFACE_ID
),
102 SetViewUIColor(B_PANEL_BACKGROUND_COLOR
);
104 // add messenger to us so add-ons can contact us
105 BMessenger
messenger(this);
106 fAddons
.AddMessenger(DUN_MESSENGER
, messenger
);
108 // create pop-up with all interfaces and "New..."/"Delete current" items
109 fInterfaceMenu
= new BPopUpMenu(kLabelCreateNew
);
110 fMenuField
= new BMenuField("Interfaces", kLabelInterface
, fInterfaceMenu
);
112 fTabView
= new BTabView("TabView", B_WIDTH_FROM_LABEL
);
113 BRect
tabViewRect(fTabView
->Bounds());
114 fAddons
.AddRect(DUN_TAB_VIEW_RECT
, tabViewRect
); // FIXME: remove
116 fStringView
= new BStringView("NoInterfacesFound",
117 kTextNoInterfacesFound
);
118 fStringView
->SetAlignment(B_ALIGN_CENTER
);
120 fCreateNewButton
= new BButton("CreateNewButton",
121 kLabelCreateNewInterface
, new BMessage(kMsgCreateNew
));
122 fCreateNewButton
->Hide();
124 fStatusView
= new BStringView("StatusView", kTextNotConnected
);
126 fConnectButton
= new BButton("ConnectButton", kLabelConnect
,
127 new BMessage(kMsgConnectButton
));
129 BLayoutBuilder::Group
<>(this, B_VERTICAL
)
133 .Add(fCreateNewButton
)
134 .AddGroup(B_HORIZONTAL
)
146 // reset, otherwise SelectInterface will not load the settings
152 DialUpView::~DialUpView()
154 SaveSettingsToFile();
157 wait_for_thread(fUpDownThread
, &tmp
);
159 // free known add-on types (these should free their known add-on types, etc.)
162 fAddons
.FindPointer(DUN_DELETE_ON_QUIT
, index
,
163 reinterpret_cast<void**>(&addon
)) == B_OK
;
170 DialUpView::AttachedToWindow()
172 fInterfaceMenu
->SetTargetForItems(this);
173 fCreateNewButton
->SetTarget(this);
174 fConnectButton
->SetTarget(this);
176 if(fListener
.InitCheck() != B_OK
) {
177 (new BAlert(kErrorTitle
, kErrorNoPPPStack
, kLabelOK
,
178 NULL
, NULL
, B_WIDTH_AS_USUAL
, B_WARNING_ALERT
))->Go(NULL
);
179 fConnectButton
->Hide();
185 DialUpView::MessageReceived(BMessage
*message
)
187 switch(message
->what
) {
188 case PPP_REPORT_MESSAGE
:
189 HandleReportMessage(message
);
192 // -------------------------------------------------
193 case kMsgCreateNew
: {
194 (new TextRequestDialog(kLabelCreateNewInterface
, kTextChooseInterfaceName
,
195 kLabelInterfaceName
))->Go(
196 new BInvoker(new BMessage(kMsgFinishCreateNew
), this));
199 case kMsgFinishCreateNew
: {
201 message
->FindInt32("which", &which
);
202 const char *name
= message
->FindString("text");
203 if(which
== 1 && name
&& strlen(name
) > 0)
204 AddInterface(name
, true);
207 fCurrentItem
->SetMarked(true);
209 // -------------------------------------------------
211 case kMsgDeleteCurrent
: {
215 fInterfaceMenu
->RemoveItem(fCurrentItem
);
216 BDirectory settings
, profile
;
217 GetPPPDirectories(&settings
, &profile
);
219 settings
.FindEntry(fCurrentItem
->Label(), &entry
);
221 profile
.FindEntry(fCurrentItem
->Label(), &entry
);
226 BMenuItem
*marked
= fInterfaceMenu
->FindMarked();
228 marked
->SetMarked(false);
232 // this stops watching the deleted interface
235 case kMsgSelectInterface
: {
237 message
->FindInt32("index", &index
);
238 SelectInterface(index
);
241 case kMsgConnectButton
: {
242 if(!fCurrentItem
|| fUpDownThread
!= -1)
245 fUpDownThread
= spawn_thread(up_down_thread
, "up_down_thread",
246 B_NORMAL_PRIORITY
, this);
247 resume_thread(fUpDownThread
);
251 BView::MessageReceived(message
);
257 DialUpView::SelectInterfaceNamed(const char *name
)
259 BMenuItem
*item
= fInterfaceMenu
->FindItem(name
);
261 int32 index
= fInterfaceMenu
->IndexOf(item
);
262 if(!item
|| index
>= CountInterfaces())
265 SelectInterface(index
);
272 DialUpView::NeedsRequest() const
274 return fGeneralAddon
? fGeneralAddon
->NeedsAuthenticationRequest() : false;
279 DialUpView::StatusView() const
286 DialUpView::ConnectButton() const
288 return fConnectButton
;
293 DialUpView::LoadSettings(bool isNew
)
295 fSettings
.MakeEmpty();
296 fProfile
.MakeEmpty();
297 BMessage
*settingsPointer
= fCurrentItem
? &fSettings
: NULL
,
298 *profilePointer
= fCurrentItem
? &fProfile
: NULL
;
300 if(fCurrentItem
&& !isNew
) {
301 BString
name("pppidf/");
302 name
<< fCurrentItem
->Label();
303 if(!ReadMessageDriverSettings(name
.String(), &fSettings
))
305 name
= "pppidf/profile/";
306 name
<< fCurrentItem
->Label();
307 if(!ReadMessageDriverSettings(name
.String(), &fProfile
))
308 profilePointer
= settingsPointer
;
312 for(int32 index
= 0; fAddons
.FindPointer(DUN_TAB_ADDON_TYPE
, index
,
313 reinterpret_cast<void**>(&addon
)) == B_OK
; index
++) {
317 if(!addon
->LoadSettings(settingsPointer
, profilePointer
, isNew
))
321 // TODO: check if settings are valid
328 DialUpView::IsModified(bool *settings
, bool *profile
)
330 *settings
= *profile
= false;
331 bool addonSettingsChanged
, addonProfileChanged
;
335 for(int32 index
= 0; fAddons
.FindPointer(DUN_TAB_ADDON_TYPE
, index
,
336 reinterpret_cast<void**>(&addon
)) == B_OK
; index
++) {
340 addon
->IsModified(&addonSettingsChanged
, &addonProfileChanged
);
341 if(addonSettingsChanged
)
343 if(addonProfileChanged
)
350 DialUpView::SaveSettings(BMessage
*settings
, BMessage
*profile
, bool saveTemporary
)
352 if(!fCurrentItem
|| !settings
|| !profile
)
356 TemplateList
<DialUpAddon
*> addons
;
358 fAddons
.FindPointer(DUN_TAB_ADDON_TYPE
, index
,
359 reinterpret_cast<void**>(&addon
)) == B_OK
; index
++) {
363 int32 insertIndex
= 0;
364 for(; insertIndex
< addons
.CountItems(); insertIndex
++)
365 if(addons
.ItemAt(insertIndex
)->Priority() <= addon
->Priority())
368 addons
.AddItem(addon
, insertIndex
);
371 settings
->AddInt32("Interface", static_cast<int32
>(fWatching
));
373 settings
->AddString("InterfaceName", fCurrentItem
->Label());
375 for(int32 index
= 0; index
< addons
.CountItems(); index
++)
376 if(!addons
.ItemAt(index
)->SaveSettings(settings
, profile
, saveTemporary
))
384 DialUpView::SaveSettingsToFile()
386 bool settingsChanged
, profileChanged
;
387 IsModified(&settingsChanged
, &profileChanged
);
388 if(!settingsChanged
&& !profileChanged
)
391 BMessage settings
, profile
;
392 if(!SaveSettings(&settings
, &profile
, false))
395 BDirectory settingsDirectory
;
396 BDirectory profileDirectory
;
397 GetPPPDirectories(&settingsDirectory
, &profileDirectory
);
398 if(settingsDirectory
.InitCheck() != B_OK
|| profileDirectory
.InitCheck() != B_OK
)
402 if(settingsChanged
) {
403 settingsDirectory
.CreateFile(fCurrentItem
->Label(), &file
);
404 WriteMessageDriverSettings(file
, settings
);
408 profileDirectory
.CreateFile(fCurrentItem
->Label(), &file
);
409 WriteMessageDriverSettings(file
, profile
);
417 DialUpView::UpDownThread()
419 SaveSettingsToFile();
420 BMessage settings
, profile
;
421 SaveSettings(&settings
, &profile
, true);
422 // save temporary profile
423 //driver_settings *temporaryProfile = MessageToDriverSettings(profile);
425 PPPInterface interface
;
426 if (fWatching
== PPP_UNDEFINED_INTERFACE_ID
) {
427 interface
= fListener
.Manager().InterfaceWithName(fCurrentItem
->Label());
428 if(interface
.InitCheck() != B_OK
)
429 interface
= fListener
.Manager().CreateInterfaceWithName(
430 fCurrentItem
->Label());
432 interface
= fWatching
;
433 //interface.SetProfile(temporaryProfile);
436 //free_driver_settings(temporaryProfile);
438 if(interface
.InitCheck() != B_OK
) {
440 fStatusView
->SetText(kTextCreationError
);
445 ppp_interface_info_t info
;
446 interface
.GetInterfaceInfo(&info
);
447 if(info
.info
.phase
== PPP_DOWN_PHASE
)
456 #define PPP_INTERFACE_SETTINGS_PATH "" // FIXME!
458 DialUpView::GetPPPDirectories(BDirectory
*settingsDirectory
,
459 BDirectory
*profileDirectory
) const
461 if(settingsDirectory
) {
462 BDirectory
settings(PPP_INTERFACE_SETTINGS_PATH
);
463 if(settings
.InitCheck() != B_OK
) {
464 create_directory(PPP_INTERFACE_SETTINGS_PATH
, 0750);
465 settings
.SetTo(PPP_INTERFACE_SETTINGS_PATH
);
468 *settingsDirectory
= settings
;
471 if(profileDirectory
) {
472 BDirectory
profile(PPP_INTERFACE_SETTINGS_PATH
"/profile");
473 if(profile
.InitCheck() != B_OK
) {
474 create_directory(PPP_INTERFACE_SETTINGS_PATH
"/profile", 0750);
475 profile
.SetTo(PPP_INTERFACE_SETTINGS_PATH
"/profile");
478 *profileDirectory
= profile
;
484 DialUpView::HandleReportMessage(BMessage
*message
)
487 message
->FindInt32("sender", &sender
);
489 send_data(sender
, B_OK
, NULL
, 0);
495 if(message
->FindInt32("interface", reinterpret_cast<int32
*>(&id
)) != B_OK
496 || (fWatching
!= PPP_UNDEFINED_INTERFACE_ID
&& id
!= fWatching
))
500 message
->FindInt32("type", &type
);
501 message
->FindInt32("code", &code
);
503 if(type
== PPP_MANAGER_REPORT
&& code
== PPP_REPORT_INTERFACE_CREATED
) {
504 PPPInterface
interface(id
);
505 if(interface
.InitCheck() != B_OK
)
508 ppp_interface_info_t info
;
509 interface
.GetInterfaceInfo(&info
);
510 if(strcasecmp(info
.info
.name
, fCurrentItem
->Label()))
514 } else if(type
== PPP_CONNECTION_REPORT
) {
515 if(fWatching
== PPP_UNDEFINED_INTERFACE_ID
)
519 } else if(type
== PPP_DESTRUCTION_REPORT
) {
520 if(fWatching
== PPP_UNDEFINED_INTERFACE_ID
)
523 WatchInterface(fListener
.Manager().InterfaceWithName(fCurrentItem
->Label()));
529 DialUpView::CreateTabs()
531 // create tabs for all registered and valid tab add-ons
532 DialUpAddon
*addon
= NULL
;
533 BView
*target
= NULL
;
534 TemplateList
<DialUpAddon
*> addons
;
536 for (int32 index
= 0;
537 fAddons
.FindPointer(DUN_TAB_ADDON_TYPE
, index
,
538 reinterpret_cast<void**>(&addon
)) == B_OK
;
540 if (!addon
|| addon
->Position() < 0)
543 int32 insertIndex
= 0;
544 for(; insertIndex
< addons
.CountItems(); insertIndex
++) {
545 if (addons
.ItemAt(insertIndex
)->Position() > addon
->Position())
549 addons
.AddItem(addon
, insertIndex
);
552 for (int32 index
= 0; index
< addons
.CountItems(); index
++) {
553 addon
= addons
.ItemAt(index
);
555 target
= addon
->CreateView();
559 fTabView
->AddTab(target
, NULL
);
565 DialUpView::UpdateStatus(int32 code
)
568 case PPP_REPORT_DEVICE_UP_FAILED
:
569 case PPP_REPORT_AUTHENTICATION_FAILED
:
570 case PPP_REPORT_DOWN_SUCCESSFUL
:
571 case PPP_REPORT_CONNECTION_LOST
: {
572 fConnectButton
->SetLabel(kLabelConnect
);
576 fConnectButton
->SetLabel(kLabelDisconnect
);
579 // maybe the status string must not be changed (codes that set fKeepLabel to false
580 // should still be handled)
581 if(fKeepLabel
&& code
!= PPP_REPORT_GOING_UP
&& code
!= PPP_REPORT_UP_SUCCESSFUL
)
584 if(fListener
.InitCheck() != B_OK
) {
585 fStatusView
->SetText(kErrorNoPPPStack
);
589 // only errors should set fKeepLabel to true
591 case PPP_REPORT_GOING_UP
:
593 fStatusView
->SetText(kTextConnecting
);
596 case PPP_REPORT_UP_SUCCESSFUL
:
598 fStatusView
->SetText(kTextConnectionEstablished
);
601 case PPP_REPORT_DOWN_SUCCESSFUL
:
602 fStatusView
->SetText(kTextNotConnected
);
605 case PPP_REPORT_DEVICE_UP_FAILED
:
607 fStatusView
->SetText(kTextDeviceUpFailed
);
610 case PPP_REPORT_AUTHENTICATION_REQUESTED
:
611 fStatusView
->SetText(kTextAuthenticating
);
614 case PPP_REPORT_AUTHENTICATION_FAILED
:
616 fStatusView
->SetText(kTextAuthenticationFailed
);
619 case PPP_REPORT_CONNECTION_LOST
:
621 fStatusView
->SetText(kTextConnectionLost
);
628 DialUpView::WatchInterface(ppp_interface_id ID
)
630 // This method can be used to update the interface's connection status.
632 if(fWatching
!= ID
) {
633 //fListener.StopWatchingInterfaces(); // FIXME
635 if(ID
== PPP_UNDEFINED_INTERFACE_ID
|| fListener
.WatchInterface(ID
))
640 PPPInterface
interface(fWatching
);
641 if(interface
.InitCheck() != B_OK
) {
642 UpdateStatus(PPP_REPORT_DOWN_SUCCESSFUL
);
646 ppp_interface_info_t info
;
647 interface
.GetInterfaceInfo(&info
);
649 // transform phase into status
650 switch(info
.info
.phase
) {
652 UpdateStatus(PPP_REPORT_DOWN_SUCCESSFUL
);
655 case PPP_TERMINATION_PHASE
:
658 case PPP_ESTABLISHED_PHASE
:
659 UpdateStatus(PPP_REPORT_UP_SUCCESSFUL
);
663 UpdateStatus(PPP_REPORT_GOING_UP
);
669 DialUpView::LoadInterfaces()
671 fInterfaceMenu
->AddSeparatorItem();
672 fInterfaceMenu
->AddItem(new BMenuItem(kLabelCreateNewInterface
,
673 new BMessage(kMsgCreateNew
)));
674 fDeleterItem
= new BMenuItem(kLabelDeleteCurrent
,
675 new BMessage(kMsgDeleteCurrent
));
676 fInterfaceMenu
->AddItem(fDeleterItem
);
678 BDirectory settingsDirectory
;
681 GetPPPDirectories(&settingsDirectory
, NULL
);
682 while(settingsDirectory
.GetNextEntry(&entry
) == B_OK
) {
684 entry
.GetPath(&path
);
685 AddInterface(path
.Leaf(), true);
692 DialUpView::LoadAddons()
694 // Load integrated add-ons:
695 // "Connection Options" tab
696 ConnectionOptionsAddon
*connectionOptionsAddon
=
697 new ConnectionOptionsAddon(&fAddons
);
698 fAddons
.AddPointer(DUN_TAB_ADDON_TYPE
, connectionOptionsAddon
);
699 fAddons
.AddPointer(DUN_DELETE_ON_QUIT
, connectionOptionsAddon
);
701 GeneralAddon
*fGeneralAddon
= new GeneralAddon(&fAddons
);
702 fAddons
.AddPointer(DUN_TAB_ADDON_TYPE
, fGeneralAddon
);
703 fAddons
.AddPointer(DUN_DELETE_ON_QUIT
, fGeneralAddon
);
706 IPCPAddon
*ipcpAddon
= new IPCPAddon(&fAddons
);
707 fAddons
.AddPointer(DUN_TAB_ADDON_TYPE
, ipcpAddon
);
708 fAddons
.AddPointer(DUN_DELETE_ON_QUIT
, ipcpAddon
);
710 PPPoEAddon
*pppoeAddon
= new PPPoEAddon(&fAddons
);
711 fAddons
.AddPointer(DUN_DEVICE_ADDON_TYPE
, pppoeAddon
);
712 fAddons
.AddPointer(DUN_DELETE_ON_QUIT
, pppoeAddon
);
714 // "PAP" authenticator
716 addon
.AddString("FriendlyName", "Plain-text Authentication");
717 addon
.AddString("TechnicalName", "PAP");
718 addon
.AddString("KernelModuleName", "pap");
719 fAddons
.AddMessage(DUN_AUTHENTICATOR_ADDON_TYPE
, &addon
);
720 // addon.MakeEmpty(); // for next authenticator
723 // load all add-ons from the add-ons folder
728 DialUpView::AddInterface(const char *name
, bool isNew
)
730 if(fInterfaceMenu
->FindItem(name
)) {
731 (new BAlert(kErrorTitle
, kErrorInterfaceExists
, kLabelOK
,
732 NULL
, NULL
, B_WIDTH_AS_USUAL
, B_WARNING_ALERT
))->Go(NULL
);
736 BMenuItem
*item
= new BMenuItem(name
, new BMessage(kMsgSelectInterface
));
737 item
->SetTarget(this);
738 int32 index
= FindNextMenuInsertionIndex(fInterfaceMenu
, name
);
739 if(index
> CountInterfaces())
740 index
= CountInterfaces();
741 fInterfaceMenu
->AddItem(item
, index
);
744 item
->SetMarked(true);
745 SelectInterface(index
, isNew
);
750 DialUpView::SelectInterface(int32 index
, bool isNew
)
752 BMenuItem
*item
= fInterfaceMenu
->FindMarked();
753 if(fCurrentItem
&& item
== fCurrentItem
)
756 if(fCurrentItem
&& !SaveSettingsToFile())
757 (new BAlert(kErrorTitle
, kErrorSavingFailed
, kLabelOK
,
758 NULL
, NULL
, B_WIDTH_AS_USUAL
, B_WARNING_ALERT
))->Go(NULL
);
760 if(index
>= CountInterfaces() || index
< 0) {
761 if(CountInterfaces() > 0)
765 WatchInterface(PPP_UNDEFINED_INTERFACE_ID
);
768 fCurrentItem
= fInterfaceMenu
->ItemAt(index
);
774 fCurrentItem
->SetMarked(true);
775 fDeleterItem
->SetEnabled(true);
776 WatchInterface(fListener
.Manager().InterfaceWithName(fCurrentItem
->Label()));
781 // tell modules to unload all settings
782 else if(!isNew
&& !LoadSettings(false)) {
783 (new BAlert(kErrorTitle
, kErrorLoadingFailed
, kLabelOK
,
784 NULL
, NULL
, B_WIDTH_AS_USUAL
, B_WARNING_ALERT
))->Go(NULL
);
786 } else if(isNew
&& !LoadSettings(true))
787 (new BAlert(kErrorTitle
, kErrorLoadingFailed
, kLabelOK
,
788 NULL
, NULL
, B_WIDTH_AS_USUAL
, B_WARNING_ALERT
))->Go(NULL
);
793 DialUpView::CountInterfaces() const
795 return fInterfaceMenu
->CountItems() - 3;
800 DialUpView::UpdateControls()
802 if(fTabView
->IsHidden() && CountInterfaces() > 0) {
803 fInterfaceMenu
->SetLabelFromMarked(true);
805 fCreateNewButton
->Hide();
807 fConnectButton
->SetEnabled(true);
808 } else if(!fTabView
->IsHidden() && CountInterfaces() == 0) {
809 fDeleterItem
->SetEnabled(false);
810 fInterfaceMenu
->SetRadioMode(false);
811 fInterfaceMenu
->Superitem()->SetLabel(kLabelCreateNew
);
814 fCreateNewButton
->Show();
815 fConnectButton
->SetEnabled(false);