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#include "DialUpView.h"
9#include "DialUpAddon.h"
10
11#include <cstring>
12#include "InterfaceUtils.h"
13#include "MessageDriverSettingsUtils.h"
14#include "TextRequestDialog.h"
15
16// built-in add-ons
17#include "ConnectionOptionsAddon.h"
18#include "GeneralAddon.h"
19#include "IPCPAddon.h"
20#include "PPPoEAddon.h"
21
22#include <PPPInterface.h>
23#include <settings_tools.h>
24#include <TemplateList.h>
25
26#include <Application.h>
27
28#include <Alert.h>
29#include <Button.h>
30#include <MenuField.h>
31#include <MenuItem.h>
32#include <Messenger.h>
33#include <PopUpMenu.h>
34#include <LayoutBuilder.h>
35#include <StringView.h>
36#include <TabView.h>
37
38#include <Directory.h>
39#include <Entry.h>
40#include <File.h>
41#include <Path.h>
42
43
44// message constants
45static const uint32 kMsgCreateNew = 'NEWI';
46static const uint32 kMsgFinishCreateNew = 'FNEW';
47static const uint32 kMsgDeleteCurrent = 'DELI';
48static const uint32 kMsgSelectInterface = 'SELI';
49static const uint32 kMsgConnectButton = 'CONI';
50
51// labels
52static const char *kLabelInterface = "Interface: ";
53static const char *kLabelInterfaceName = "Interface Name: ";
54static const char *kLabelCreateNewInterface = "Create New Interface";
55static const char *kLabelCreateNew = "Create New...";
56static const char *kLabelDeleteCurrent = "Delete Current";
57static const char *kLabelConnect = "Connect";
58static const char *kLabelDisconnect = "Disconnect";
59static const char *kLabelOK = "OK";
60
61// connection status strings
62static const char *kTextConnecting = "Connecting...";
63static const char *kTextConnectionEstablished = "Connection established.";
64static const char *kTextNotConnected = "Not connected.";
65static const char *kTextDeviceUpFailed = "Failed to connect.";
66static const char *kTextAuthenticating = "Authenticating...";
67static const char *kTextAuthenticationFailed = "Authentication failed!";
68static const char *kTextConnectionLost = "Connection lost!";
69static const char *kTextCreationError = "Error creating interface!";
70static const char *kTextNoInterfacesFound = "Please create a new interface...";
71static const char *kTextChooseInterfaceName = "Please choose a new name for this "
72											"interface.";
73
74// error strings for alerts
75static const char *kErrorTitle = "Error";
76static const char *kErrorNoPPPStack = "Error: Could not access the PPP stack!";
77static const char *kErrorInterfaceExists = "Error: An interface with this name "
78										"already exists!";
79static const char *kErrorLoadingFailed = "Error: Failed loading interface! The "
80										"current settings will be deleted.";
81static const char *kErrorSavingFailed = "Error: Failed saving interface settings!";
82
83
84static
85status_t
86up_down_thread(void *data)
87{
88	static_cast<DialUpView*>(data)->UpDownThread();
89	return B_OK;
90}
91
92
93DialUpView::DialUpView()
94	: BView("DialUpView", 0),
95	fListener(this),
96	fUpDownThread(-1),
97	fDriverSettings(NULL),
98	fCurrentItem(NULL),
99	fWatching(PPP_UNDEFINED_INTERFACE_ID),
100	fKeepLabel(false)
101{
102	SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
103
104	// add messenger to us so add-ons can contact us
105	BMessenger messenger(this);
106	fAddons.AddMessenger(DUN_MESSENGER, messenger);
107
108	// create pop-up with all interfaces and "New..."/"Delete current" items
109	fInterfaceMenu = new BPopUpMenu(kLabelCreateNew);
110	fMenuField = new BMenuField("Interfaces", kLabelInterface, fInterfaceMenu);
111
112	fTabView = new BTabView("TabView", B_WIDTH_FROM_LABEL);
113	BRect tabViewRect(fTabView->Bounds());
114	fAddons.AddRect(DUN_TAB_VIEW_RECT, tabViewRect); // FIXME: remove
115
116	fStringView = new BStringView("NoInterfacesFound",
117		kTextNoInterfacesFound);
118	fStringView->SetAlignment(B_ALIGN_CENTER);
119	fStringView->Hide();
120	fCreateNewButton = new BButton("CreateNewButton",
121		kLabelCreateNewInterface, new BMessage(kMsgCreateNew));
122	fCreateNewButton->Hide();
123
124	fStatusView = new BStringView("StatusView", kTextNotConnected);
125
126	fConnectButton = new BButton("ConnectButton", kLabelConnect,
127		new BMessage(kMsgConnectButton));
128
129	BLayoutBuilder::Group<>(this, B_VERTICAL)
130		.Add(fMenuField)
131		.Add(fTabView)
132		.Add(fStringView)
133		.Add(fCreateNewButton)
134		.AddGroup(B_HORIZONTAL)
135			.Add(fStatusView)
136			.AddGlue()
137			.Add(fConnectButton)
138		.End()
139	.End();
140
141	// initialize
142	LoadInterfaces();
143	LoadAddons();
144	CreateTabs();
145	fCurrentItem = NULL;
146		// reset, otherwise SelectInterface will not load the settings
147	SelectInterface(0);
148	UpdateControls();
149}
150
151
152DialUpView::~DialUpView()
153{
154	SaveSettingsToFile();
155
156	int32 tmp;
157	wait_for_thread(fUpDownThread, &tmp);
158
159	// free known add-on types (these should free their known add-on types, etc.)
160	DialUpAddon *addon;
161	for(int32 index = 0;
162			fAddons.FindPointer(DUN_DELETE_ON_QUIT, index,
163				reinterpret_cast<void**>(&addon)) == B_OK;
164			index++)
165		delete addon;
166}
167
168
169void
170DialUpView::AttachedToWindow()
171{
172	fInterfaceMenu->SetTargetForItems(this);
173	fCreateNewButton->SetTarget(this);
174	fConnectButton->SetTarget(this);
175
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();
180	}
181}
182
183
184void
185DialUpView::MessageReceived(BMessage *message)
186{
187	switch(message->what) {
188		case PPP_REPORT_MESSAGE:
189			HandleReportMessage(message);
190		break;
191
192		// -------------------------------------------------
193		case kMsgCreateNew: {
194			(new TextRequestDialog(kLabelCreateNewInterface, kTextChooseInterfaceName,
195					kLabelInterfaceName))->Go(
196				new BInvoker(new BMessage(kMsgFinishCreateNew), this));
197		} break;
198
199		case kMsgFinishCreateNew: {
200			int32 which;
201			message->FindInt32("which", &which);
202			const char *name = message->FindString("text");
203			if(which == 1 && name && strlen(name) > 0)
204				AddInterface(name, true);
205
206			if(fCurrentItem)
207				fCurrentItem->SetMarked(true);
208		} break;
209		// -------------------------------------------------
210
211		case kMsgDeleteCurrent: {
212			if(!fCurrentItem)
213				return;
214
215			fInterfaceMenu->RemoveItem(fCurrentItem);
216			BDirectory settings, profile;
217			GetPPPDirectories(&settings, &profile);
218			BEntry entry;
219			settings.FindEntry(fCurrentItem->Label(), &entry);
220			entry.Remove();
221			profile.FindEntry(fCurrentItem->Label(), &entry);
222			entry.Remove();
223			delete fCurrentItem;
224			fCurrentItem = NULL;
225
226			BMenuItem *marked = fInterfaceMenu->FindMarked();
227			if(marked)
228				marked->SetMarked(false);
229
230			UpdateControls();
231			SelectInterface(0);
232				// this stops watching the deleted interface
233		} break;
234
235		case kMsgSelectInterface: {
236			int32 index;
237			message->FindInt32("index", &index);
238			SelectInterface(index);
239		} break;
240
241		case kMsgConnectButton: {
242			if(!fCurrentItem || fUpDownThread != -1)
243				return;
244
245			fUpDownThread = spawn_thread(up_down_thread, "up_down_thread",
246				B_NORMAL_PRIORITY, this);
247			resume_thread(fUpDownThread);
248		} break;
249
250		default:
251			BView::MessageReceived(message);
252	}
253}
254
255
256bool
257DialUpView::SelectInterfaceNamed(const char *name)
258{
259	BMenuItem *item = fInterfaceMenu->FindItem(name);
260
261	int32 index = fInterfaceMenu->IndexOf(item);
262	if(!item || index >= CountInterfaces())
263		return false;
264
265	SelectInterface(index);
266
267	return true;
268}
269
270
271bool
272DialUpView::NeedsRequest() const
273{
274	return fGeneralAddon ? fGeneralAddon->NeedsAuthenticationRequest() : false;
275}
276
277
278BView*
279DialUpView::StatusView() const
280{
281	return fStatusView;
282}
283
284
285BView*
286DialUpView::ConnectButton() const
287{
288	return fConnectButton;
289}
290
291
292bool
293DialUpView::LoadSettings(bool isNew)
294{
295	fSettings.MakeEmpty();
296	fProfile.MakeEmpty();
297	BMessage *settingsPointer = fCurrentItem ? &fSettings : NULL,
298		*profilePointer = fCurrentItem ? &fProfile : NULL;
299
300	if(fCurrentItem && !isNew) {
301		BString name("pppidf/");
302		name << fCurrentItem->Label();
303		if(!ReadMessageDriverSettings(name.String(), &fSettings))
304			return false;
305		name = "pppidf/profile/";
306		name << fCurrentItem->Label();
307		if(!ReadMessageDriverSettings(name.String(), &fProfile))
308			profilePointer = settingsPointer;
309	}
310
311	DialUpAddon *addon;
312	for(int32 index = 0; fAddons.FindPointer(DUN_TAB_ADDON_TYPE, index,
313			reinterpret_cast<void**>(&addon)) == B_OK; index++) {
314		if(!addon)
315			continue;
316
317		if(!addon->LoadSettings(settingsPointer, profilePointer, isNew))
318			return false;
319	}
320
321	// TODO: check if settings are valid
322
323	return true;
324}
325
326
327void
328DialUpView::IsModified(bool *settings, bool *profile)
329{
330	*settings = *profile = false;
331	bool addonSettingsChanged, addonProfileChanged;
332		// for current addon
333
334	DialUpAddon *addon;
335	for(int32 index = 0; fAddons.FindPointer(DUN_TAB_ADDON_TYPE, index,
336			reinterpret_cast<void**>(&addon)) == B_OK; index++) {
337		if(!addon)
338			continue;
339
340		addon->IsModified(&addonSettingsChanged, &addonProfileChanged);
341		if(addonSettingsChanged)
342			*settings = true;
343		if(addonProfileChanged)
344			*profile = true;
345	}
346}
347
348
349bool
350DialUpView::SaveSettings(BMessage *settings, BMessage *profile, bool saveTemporary)
351{
352	if(!fCurrentItem || !settings || !profile)
353		return false;
354
355	DialUpAddon *addon;
356	TemplateList<DialUpAddon*> addons;
357	for(int32 index = 0;
358			fAddons.FindPointer(DUN_TAB_ADDON_TYPE, index,
359				reinterpret_cast<void**>(&addon)) == B_OK; index++) {
360		if(!addon)
361			continue;
362
363		int32 insertIndex = 0;
364		for(; insertIndex < addons.CountItems(); insertIndex++)
365			if(addons.ItemAt(insertIndex)->Priority() <= addon->Priority())
366				break;
367
368		addons.AddItem(addon, insertIndex);
369	}
370
371	settings->AddInt32("Interface", static_cast<int32>(fWatching));
372	if(fCurrentItem)
373		settings->AddString("InterfaceName", fCurrentItem->Label());
374
375	for(int32 index = 0; index < addons.CountItems(); index++)
376		if(!addons.ItemAt(index)->SaveSettings(settings, profile, saveTemporary))
377			return false;
378
379	return true;
380}
381
382
383bool
384DialUpView::SaveSettingsToFile()
385{
386	bool settingsChanged, profileChanged;
387	IsModified(&settingsChanged, &profileChanged);
388	if(!settingsChanged && !profileChanged)
389		return true;
390
391	BMessage settings, profile;
392	if(!SaveSettings(&settings, &profile, false))
393		return false;
394
395	BDirectory settingsDirectory;
396	BDirectory profileDirectory;
397	GetPPPDirectories(&settingsDirectory, &profileDirectory);
398	if(settingsDirectory.InitCheck() != B_OK || profileDirectory.InitCheck() != B_OK)
399		return false;
400
401	BFile file;
402	if(settingsChanged) {
403		settingsDirectory.CreateFile(fCurrentItem->Label(), &file);
404		WriteMessageDriverSettings(file, settings);
405	}
406
407	if(profileChanged) {
408		profileDirectory.CreateFile(fCurrentItem->Label(), &file);
409		WriteMessageDriverSettings(file, profile);
410	}
411
412	return true;
413}
414
415
416void
417DialUpView::UpDownThread()
418{
419	SaveSettingsToFile();
420	BMessage settings, profile;
421	SaveSettings(&settings, &profile, true);
422		// save temporary profile
423	//driver_settings *temporaryProfile = MessageToDriverSettings(profile);
424
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());
431	} else {
432		interface = fWatching;
433		//interface.SetProfile(temporaryProfile);
434	}
435
436	//free_driver_settings(temporaryProfile);
437
438	if(interface.InitCheck() != B_OK) {
439		Window()->Lock();
440		fStatusView->SetText(kTextCreationError);
441		Window()->Unlock();
442		return;
443	}
444
445	ppp_interface_info_t info;
446	interface.GetInterfaceInfo(&info);
447	if(info.info.phase == PPP_DOWN_PHASE)
448		interface.Up();
449	else
450		interface.Down();
451
452	fUpDownThread = -1;
453}
454
455
456#define PPP_INTERFACE_SETTINGS_PATH "" // FIXME!
457void
458DialUpView::GetPPPDirectories(BDirectory *settingsDirectory,
459	BDirectory *profileDirectory) const
460{
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);
466		}
467
468		*settingsDirectory = settings;
469	}
470
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");
476		}
477
478		*profileDirectory = profile;
479	}
480}
481
482
483void
484DialUpView::HandleReportMessage(BMessage *message)
485{
486	thread_id sender;
487	message->FindInt32("sender", &sender);
488
489	send_data(sender, B_OK, NULL, 0);
490
491	if(!fCurrentItem)
492		return;
493
494	ppp_interface_id id;
495	if(message->FindInt32("interface", reinterpret_cast<int32*>(&id)) != B_OK
496			|| (fWatching != PPP_UNDEFINED_INTERFACE_ID && id != fWatching))
497		return;
498
499	int32 type, code;
500	message->FindInt32("type", &type);
501	message->FindInt32("code", &code);
502
503	if(type == PPP_MANAGER_REPORT && code == PPP_REPORT_INTERFACE_CREATED) {
504		PPPInterface interface(id);
505		if(interface.InitCheck() != B_OK)
506			return;
507
508		ppp_interface_info_t info;
509		interface.GetInterfaceInfo(&info);
510		if(strcasecmp(info.info.name, fCurrentItem->Label()))
511			return;
512
513		WatchInterface(id);
514	} else if(type == PPP_CONNECTION_REPORT) {
515		if(fWatching == PPP_UNDEFINED_INTERFACE_ID)
516			return;
517
518		UpdateStatus(code);
519	} else if(type == PPP_DESTRUCTION_REPORT) {
520		if(fWatching == PPP_UNDEFINED_INTERFACE_ID)
521			return;
522
523		WatchInterface(fListener.Manager().InterfaceWithName(fCurrentItem->Label()));
524	}
525}
526
527
528void
529DialUpView::CreateTabs()
530{
531	// create tabs for all registered and valid tab add-ons
532	DialUpAddon *addon = NULL;
533	BView *target = NULL;
534	TemplateList<DialUpAddon*> addons;
535
536	for (int32 index = 0;
537			fAddons.FindPointer(DUN_TAB_ADDON_TYPE, index,
538				reinterpret_cast<void**>(&addon)) == B_OK;
539			index++) {
540		if (!addon || addon->Position() < 0)
541			continue;
542
543		int32 insertIndex = 0;
544		for(; insertIndex < addons.CountItems(); insertIndex++) {
545			if (addons.ItemAt(insertIndex)->Position() > addon->Position())
546				break;
547		}
548
549		addons.AddItem(addon, insertIndex);
550	}
551
552	for (int32 index = 0; index < addons.CountItems(); index++) {
553		addon = addons.ItemAt(index);
554
555		target = addon->CreateView();
556		if (target == NULL)
557			continue;
558
559		fTabView->AddTab(target, NULL);
560	}
561}
562
563
564void
565DialUpView::UpdateStatus(int32 code)
566{
567	switch(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);
573		} break;
574
575		default:
576			fConnectButton->SetLabel(kLabelDisconnect);
577	}
578
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)
582		return;
583
584	if(fListener.InitCheck() != B_OK) {
585		fStatusView->SetText(kErrorNoPPPStack);
586		return;
587	}
588
589	// only errors should set fKeepLabel to true
590	switch(code) {
591		case PPP_REPORT_GOING_UP:
592			fKeepLabel = false;
593			fStatusView->SetText(kTextConnecting);
594		break;
595
596		case PPP_REPORT_UP_SUCCESSFUL:
597			fKeepLabel = false;
598			fStatusView->SetText(kTextConnectionEstablished);
599		break;
600
601		case PPP_REPORT_DOWN_SUCCESSFUL:
602			fStatusView->SetText(kTextNotConnected);
603		break;
604
605		case PPP_REPORT_DEVICE_UP_FAILED:
606			fKeepLabel = true;
607			fStatusView->SetText(kTextDeviceUpFailed);
608		break;
609
610		case PPP_REPORT_AUTHENTICATION_REQUESTED:
611			fStatusView->SetText(kTextAuthenticating);
612		break;
613
614		case PPP_REPORT_AUTHENTICATION_FAILED:
615			fKeepLabel = true;
616			fStatusView->SetText(kTextAuthenticationFailed);
617		break;
618
619		case PPP_REPORT_CONNECTION_LOST:
620			fKeepLabel = true;
621			fStatusView->SetText(kTextConnectionLost);
622		break;
623	}
624}
625
626
627void
628DialUpView::WatchInterface(ppp_interface_id ID)
629{
630	// This method can be used to update the interface's connection status.
631
632	if(fWatching != ID) {
633		//fListener.StopWatchingInterfaces(); // FIXME
634
635		if(ID == PPP_UNDEFINED_INTERFACE_ID || fListener.WatchInterface(ID))
636			fWatching = ID;
637	}
638
639	// update status
640	PPPInterface interface(fWatching);
641	if(interface.InitCheck() != B_OK) {
642		UpdateStatus(PPP_REPORT_DOWN_SUCCESSFUL);
643		return;
644	}
645
646	ppp_interface_info_t info;
647	interface.GetInterfaceInfo(&info);
648
649	// transform phase into status
650	switch(info.info.phase) {
651		case PPP_DOWN_PHASE:
652			UpdateStatus(PPP_REPORT_DOWN_SUCCESSFUL);
653		break;
654
655		case PPP_TERMINATION_PHASE:
656		break;
657
658		case PPP_ESTABLISHED_PHASE:
659			UpdateStatus(PPP_REPORT_UP_SUCCESSFUL);
660		break;
661
662		default:
663			UpdateStatus(PPP_REPORT_GOING_UP);
664	}
665}
666
667
668void
669DialUpView::LoadInterfaces()
670{
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);
677
678	BDirectory settingsDirectory;
679	BEntry entry;
680	BPath path;
681	GetPPPDirectories(&settingsDirectory, NULL);
682	while(settingsDirectory.GetNextEntry(&entry) == B_OK) {
683		if(entry.IsFile()) {
684			entry.GetPath(&path);
685			AddInterface(path.Leaf(), true);
686		}
687	}
688}
689
690
691void
692DialUpView::LoadAddons()
693{
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);
700	// "General" tab
701	GeneralAddon *fGeneralAddon = new GeneralAddon(&fAddons);
702	fAddons.AddPointer(DUN_TAB_ADDON_TYPE, fGeneralAddon);
703	fAddons.AddPointer(DUN_DELETE_ON_QUIT, fGeneralAddon);
704
705	// "IPCP" protocol
706	IPCPAddon *ipcpAddon = new IPCPAddon(&fAddons);
707	fAddons.AddPointer(DUN_TAB_ADDON_TYPE, ipcpAddon);
708	fAddons.AddPointer(DUN_DELETE_ON_QUIT, ipcpAddon);
709	// "PPPoE" device
710	PPPoEAddon *pppoeAddon = new PPPoEAddon(&fAddons);
711	fAddons.AddPointer(DUN_DEVICE_ADDON_TYPE, pppoeAddon);
712	fAddons.AddPointer(DUN_DELETE_ON_QUIT, pppoeAddon);
713
714	// "PAP" authenticator
715	BMessage addon;
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
721
722	// TODO:
723	// load all add-ons from the add-ons folder
724}
725
726
727void
728DialUpView::AddInterface(const char *name, bool isNew)
729{
730	if(fInterfaceMenu->FindItem(name)) {
731		(new BAlert(kErrorTitle, kErrorInterfaceExists, kLabelOK,
732			NULL, NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(NULL);
733		return;
734	}
735
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);
742	UpdateControls();
743
744	item->SetMarked(true);
745	SelectInterface(index, isNew);
746}
747
748
749void
750DialUpView::SelectInterface(int32 index, bool isNew)
751{
752	BMenuItem *item = fInterfaceMenu->FindMarked();
753	if(fCurrentItem && item == fCurrentItem)
754		return;
755
756	if(fCurrentItem && !SaveSettingsToFile())
757		(new BAlert(kErrorTitle, kErrorSavingFailed, kLabelOK,
758			NULL, NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(NULL);
759
760	if(index >= CountInterfaces() || index < 0) {
761		if(CountInterfaces() > 0)
762			SelectInterface(0);
763		else {
764			fCurrentItem = NULL;
765			WatchInterface(PPP_UNDEFINED_INTERFACE_ID);
766		}
767	} else {
768		fCurrentItem = fInterfaceMenu->ItemAt(index);
769		if(!fCurrentItem) {
770			SelectInterface(0);
771			return;
772		}
773
774		fCurrentItem->SetMarked(true);
775		fDeleterItem->SetEnabled(true);
776		WatchInterface(fListener.Manager().InterfaceWithName(fCurrentItem->Label()));
777	}
778
779	if(!fCurrentItem)
780		LoadSettings(false);
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);
785		LoadSettings(true);
786	} else if(isNew && !LoadSettings(true))
787		(new BAlert(kErrorTitle, kErrorLoadingFailed, kLabelOK,
788			NULL, NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(NULL);
789}
790
791
792int32
793DialUpView::CountInterfaces() const
794{
795	return fInterfaceMenu->CountItems() - 3;
796}
797
798
799void
800DialUpView::UpdateControls()
801{
802	if(fTabView->IsHidden() && CountInterfaces() > 0) {
803		fInterfaceMenu->SetLabelFromMarked(true);
804		fStringView->Hide();
805		fCreateNewButton->Hide();
806		fTabView->Show();
807		fConnectButton->SetEnabled(true);
808	} else if(!fTabView->IsHidden() && CountInterfaces() == 0) {
809		fDeleterItem->SetEnabled(false);
810		fInterfaceMenu->SetRadioMode(false);
811		fInterfaceMenu->Superitem()->SetLabel(kLabelCreateNew);
812		fTabView->Hide();
813		fStringView->Show();
814		fCreateNewButton->Show();
815		fConnectButton->SetEnabled(false);
816	}
817}
818