1/* -----------------------------------------------------------------------
2 * Copyright (c) 2003-2004 Waldemar Kornewald, Waldemar.Kornewald@web.de
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 * ----------------------------------------------------------------------- */
22
23#include "DialUpView.h"
24#include "DialUpAddon.h"
25
26#include <cstring>
27#include "InterfaceUtils.h"
28#include "MessageDriverSettingsUtils.h"
29#include "TextRequestDialog.h"
30
31// built-in add-ons
32#include "ConnectionOptionsAddon.h"
33#include "GeneralAddon.h"
34#include "IPCPAddon.h"
35#include "PPPoEAddon.h"
36
37#include <PPPInterface.h>
38#include <settings_tools.h>
39#include <TemplateList.h>
40
41#include <Application.h>
42
43#include <Alert.h>
44#include <Button.h>
45#include <MenuField.h>
46#include <MenuItem.h>
47#include <Messenger.h>
48#include <PopUpMenu.h>
49#include <StringView.h>
50#include <TabView.h>
51
52#include <Directory.h>
53#include <Entry.h>
54#include <File.h>
55#include <Path.h>
56
57
58// message constants
59static const uint32 kMsgCreateNew = 'NEWI';
60static const uint32 kMsgFinishCreateNew = 'FNEW';
61static const uint32 kMsgDeleteCurrent = 'DELI';
62static const uint32 kMsgSelectInterface = 'SELI';
63static const uint32 kMsgConnectButton = 'CONI';
64
65// labels
66#ifdef LANG_GERMAN
67static const char *kLabelInterface = "Verbindung: ";
68static const char *kLabelInterfaceName = "Verbindungs-Name: ";
69static const char *kLabelCreateNewInterface = "Neue Verbindung Erstellen";
70static const char *kLabelCreateNew = "Neu...";
71static const char *kLabelDeleteCurrent = "Auswahl L��schen";
72static const char *kLabelConnect = "Verbinden";
73static const char *kLabelDisconnect = "Trennen";
74static const char *kLabelOK = "OK";
75#else
76static const char *kLabelInterface = "Interface: ";
77static const char *kLabelInterfaceName = "Interface Name: ";
78static const char *kLabelCreateNewInterface = "Create New Interface";
79static const char *kLabelCreateNew = "Create New...";
80static const char *kLabelDeleteCurrent = "Delete Current";
81static const char *kLabelConnect = "Connect";
82static const char *kLabelDisconnect = "Disconnect";
83static const char *kLabelOK = "OK";
84#endif
85
86// connection status strings
87#ifdef LANG_GERMAN
88static const char *kTextConnecting = "Verbinde...";
89static const char *kTextConnectionEstablished = "Verbindung hergestellt.";
90static const char *kTextNotConnected = "Nicht verbunden.";
91static const char *kTextDeviceUpFailed = "Konnte Verbindung nicht aufbauen.";
92static const char *kTextAuthenticating = "Authentifizierung...";
93static const char *kTextAuthenticationFailed = "Authentifizierung fehlgeschlagen!";
94static const char *kTextConnectionLost = "Verbindung verloren!";
95static const char *kTextCreationError = "Fehler beim Initialisieren!";
96static const char *kTextNoInterfacesFound = "Bitte erstellen Sie eine neue "
97											"Verbindung.";
98static const char *kTextChooseInterfaceName = "Bitte denken Sie sich einen neuen "
99											"Namen f��r diese Verbindung aus.";
100#else
101static const char *kTextConnecting = "Connecting...";
102static const char *kTextConnectionEstablished = "Connection established.";
103static const char *kTextNotConnected = "Not connected.";
104static const char *kTextDeviceUpFailed = "Failed to connect.";
105static const char *kTextAuthenticating = "Authenticating...";
106static const char *kTextAuthenticationFailed = "Authentication failed!";
107static const char *kTextConnectionLost = "Connection lost!";
108static const char *kTextCreationError = "Error creating interface!";
109static const char *kTextNoInterfacesFound = "Please create a new interface...";
110static const char *kTextChooseInterfaceName = "Please choose a new name for this "
111											"interface.";
112#endif
113
114// error strings for alerts
115#ifdef LANG_GERMAN
116static const char *kErrorTitle = "Fehler";
117static const char *kErrorNoPPPStack = "Fehler: Kein Zugriff auf den PPP Stack!";
118static const char *kErrorInterfaceExists = "Fehler: Eine Verbindung mit diesem Namen "
119										"existiert bereits!";
120static const char *kErrorLoadingFailed = "Fehler: Konfiguration ist fehlerhaft! Die "
121										"Einstellungen werden zur��ckgesetzt.";
122static const char *kErrorSavingFailed = "Fehler: Speichern der Einstellungen ist "
123										"fehlgeschlagen!";
124#else
125static const char *kErrorTitle = "Error";
126static const char *kErrorNoPPPStack = "Error: Could not access the PPP stack!";
127static const char *kErrorInterfaceExists = "Error: An interface with this name "
128										"already exists!";
129static const char *kErrorLoadingFailed = "Error: Failed loading interface! The "
130										"current settings will be deleted.";
131static const char *kErrorSavingFailed = "Error: Failed saving interface settings!";
132#endif
133
134
135static
136status_t
137up_down_thread(void *data)
138{
139	static_cast<DialUpView*>(data)->UpDownThread();
140	return B_OK;
141}
142
143
144DialUpView::DialUpView(BRect frame)
145	: BView(frame, "DialUpView", B_FOLLOW_ALL, 0),
146	fListener(this),
147	fUpDownThread(-1),
148	fDriverSettings(NULL),
149	fCurrentItem(NULL),
150	fWatching(PPP_UNDEFINED_INTERFACE_ID),
151	fKeepLabel(false)
152{
153	BRect bounds = Bounds();
154		// for caching
155	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
156
157	// add messenger to us so add-ons can contact us
158	BMessenger messenger(this);
159	fAddons.AddMessenger(DUN_MESSENGER, messenger);
160
161	// create pop-up with all interfaces and "New..."/"Delete current" items
162	fInterfaceMenu = new BPopUpMenu(kLabelCreateNew);
163	BRect rect = bounds;
164	rect.InsetBy(5, 5);
165	rect.bottom = rect.top + 20;
166	fMenuField = new BMenuField(rect, "Interfaces", kLabelInterface, fInterfaceMenu);
167	fMenuField->SetDivider(StringWidth(fMenuField->Label()) + 5);
168
169	rect.top = rect.bottom + 10;
170	rect.bottom = bounds.bottom
171		- 20 // height of bottom controls
172		- 20; // space for bottom controls
173	fTabView = new BTabView(rect, "TabView", B_WIDTH_FROM_LABEL);
174	BRect tabViewRect(fTabView->Bounds());
175	tabViewRect.bottom -= fTabView->TabHeight();
176	fAddons.AddRect(DUN_TAB_VIEW_RECT, tabViewRect);
177
178	BRect tmpRect(rect);
179	tmpRect.top += (tmpRect.Height() - 15) / 2;
180	tmpRect.bottom = tmpRect.top + 15;
181	fStringView = new BStringView(tmpRect, "NoInterfacesFound",
182		kTextNoInterfacesFound);
183	fStringView->SetAlignment(B_ALIGN_CENTER);
184	fStringView->Hide();
185	tmpRect.top = tmpRect.bottom + 10;
186	tmpRect.bottom = tmpRect.top + 25;
187	fCreateNewButton = new BButton(tmpRect, "CreateNewButton",
188		kLabelCreateNewInterface, new BMessage(kMsgCreateNew));
189	fCreateNewButton->ResizeToPreferred();
190	tmpRect.left = (rect.Width() - fCreateNewButton->Bounds().Width()) / 2 + rect.left;
191	fCreateNewButton->MoveTo(tmpRect.left, tmpRect.top);
192	fCreateNewButton->Hide();
193
194	rect.top = rect.bottom + 15;
195	rect.bottom = rect.top + 15;
196	rect.right = rect.left + 200;
197	fStatusView = new BStringView(rect, "StatusView", kTextNotConnected, B_FOLLOW_BOTTOM);
198
199	rect.InsetBy(0, -5);
200	rect.left = rect.right + 5;
201	rect.right = bounds.right - 5;
202	fConnectButton = new BButton(rect, "ConnectButton", kLabelConnect,
203		new BMessage(kMsgConnectButton), B_FOLLOW_BOTTOM);
204
205	AddChild(fMenuField);
206	AddChild(fTabView);
207	AddChild(fStringView);
208	AddChild(fCreateNewButton);
209	AddChild(fStatusView);
210	AddChild(fConnectButton);
211
212	// initialize
213	LoadInterfaces();
214	LoadAddons();
215	CreateTabs();
216	fCurrentItem = NULL;
217		// reset, otherwise SelectInterface will not load the settings
218	SelectInterface(0);
219	UpdateControls();
220}
221
222
223DialUpView::~DialUpView()
224{
225	SaveSettingsToFile();
226
227	int32 tmp;
228	wait_for_thread(fUpDownThread, &tmp);
229
230	// free known add-on types (these should free their known add-on types, etc.)
231	DialUpAddon *addon;
232	for(int32 index = 0;
233			fAddons.FindPointer(DUN_DELETE_ON_QUIT, index,
234				reinterpret_cast<void**>(&addon)) == B_OK;
235			index++)
236		delete addon;
237}
238
239
240void
241DialUpView::AttachedToWindow()
242{
243	fInterfaceMenu->SetTargetForItems(this);
244	fCreateNewButton->SetTarget(this);
245	fConnectButton->SetTarget(this);
246
247	if(fListener.InitCheck() != B_OK) {
248		(new BAlert(kErrorTitle, kErrorNoPPPStack, kLabelOK,
249			NULL, NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(NULL);
250		fConnectButton->Hide();
251	}
252}
253
254
255void
256DialUpView::MessageReceived(BMessage *message)
257{
258	switch(message->what) {
259		case PPP_REPORT_MESSAGE:
260			HandleReportMessage(message);
261		break;
262
263		// -------------------------------------------------
264		case kMsgCreateNew: {
265			(new TextRequestDialog(kLabelCreateNewInterface, kTextChooseInterfaceName,
266					kLabelInterfaceName))->Go(
267				new BInvoker(new BMessage(kMsgFinishCreateNew), this));
268		} break;
269
270		case kMsgFinishCreateNew: {
271			int32 which;
272			message->FindInt32("which", &which);
273			const char *name = message->FindString("text");
274			if(which == 1 && name && strlen(name) > 0)
275				AddInterface(name, true);
276
277			if(fCurrentItem)
278				fCurrentItem->SetMarked(true);
279		} break;
280		// -------------------------------------------------
281
282		case kMsgDeleteCurrent: {
283			if(!fCurrentItem)
284				return;
285
286			fInterfaceMenu->RemoveItem(fCurrentItem);
287			BDirectory settings, profile;
288			GetPPPDirectories(&settings, &profile);
289			BEntry entry;
290			settings.FindEntry(fCurrentItem->Label(), &entry);
291			entry.Remove();
292			profile.FindEntry(fCurrentItem->Label(), &entry);
293			entry.Remove();
294			delete fCurrentItem;
295			fCurrentItem = NULL;
296
297			BMenuItem *marked = fInterfaceMenu->FindMarked();
298			if(marked)
299				marked->SetMarked(false);
300
301			UpdateControls();
302			SelectInterface(0);
303				// this stops watching the deleted interface
304		} break;
305
306		case kMsgSelectInterface: {
307			int32 index;
308			message->FindInt32("index", &index);
309			SelectInterface(index);
310		} break;
311
312		case kMsgConnectButton: {
313			if(!fCurrentItem || fUpDownThread != -1)
314				return;
315
316			fUpDownThread = spawn_thread(up_down_thread, "up_down_thread",
317				B_NORMAL_PRIORITY, this);
318			resume_thread(fUpDownThread);
319		} break;
320
321		default:
322			BView::MessageReceived(message);
323	}
324}
325
326
327bool
328DialUpView::SelectInterfaceNamed(const char *name)
329{
330	BMenuItem *item = fInterfaceMenu->FindItem(name);
331
332	int32 index = fInterfaceMenu->IndexOf(item);
333	if(!item || index >= CountInterfaces())
334		return false;
335
336	SelectInterface(index);
337
338	return true;
339}
340
341
342bool
343DialUpView::NeedsRequest() const
344{
345	return fGeneralAddon ? fGeneralAddon->NeedsAuthenticationRequest() : false;
346}
347
348
349BView*
350DialUpView::AuthenticationView() const
351{
352	return fGeneralAddon ? fGeneralAddon->AuthenticationView() : NULL;
353}
354
355
356BView*
357DialUpView::StatusView() const
358{
359	return fStatusView;
360}
361
362
363BView*
364DialUpView::ConnectButton() const
365{
366	return fConnectButton;
367}
368
369
370bool
371DialUpView::LoadSettings(bool isNew)
372{
373	fSettings.MakeEmpty();
374	fProfile.MakeEmpty();
375	BMessage *settingsPointer = fCurrentItem ? &fSettings : NULL,
376		*profilePointer = fCurrentItem ? &fProfile : NULL;
377
378	if(fCurrentItem && !isNew) {
379		BString name("pppidf/");
380		name << fCurrentItem->Label();
381		if(!ReadMessageDriverSettings(name.String(), &fSettings))
382			return false;
383		name = "pppidf/profile/";
384		name << fCurrentItem->Label();
385		if(!ReadMessageDriverSettings(name.String(), &fProfile))
386			profilePointer = settingsPointer;
387	}
388
389	DialUpAddon *addon;
390	for(int32 index = 0; fAddons.FindPointer(DUN_TAB_ADDON_TYPE, index,
391			reinterpret_cast<void**>(&addon)) == B_OK; index++) {
392		if(!addon)
393			continue;
394
395		if(!addon->LoadSettings(settingsPointer, profilePointer, isNew))
396			return false;
397	}
398
399	// TODO: check if settings are valid
400
401	return true;
402}
403
404
405void
406DialUpView::IsModified(bool *settings, bool *profile)
407{
408	*settings = *profile = false;
409	bool addonSettingsChanged, addonProfileChanged;
410		// for current addon
411
412	DialUpAddon *addon;
413	for(int32 index = 0; fAddons.FindPointer(DUN_TAB_ADDON_TYPE, index,
414			reinterpret_cast<void**>(&addon)) == B_OK; index++) {
415		if(!addon)
416			continue;
417
418		addon->IsModified(&addonSettingsChanged, &addonProfileChanged);
419		if(addonSettingsChanged)
420			*settings = true;
421		if(addonProfileChanged)
422			*profile = true;
423	}
424}
425
426
427bool
428DialUpView::SaveSettings(BMessage *settings, BMessage *profile, bool saveTemporary)
429{
430	if(!fCurrentItem || !settings || !profile)
431		return false;
432
433	DialUpAddon *addon;
434	TemplateList<DialUpAddon*> addons;
435	for(int32 index = 0;
436			fAddons.FindPointer(DUN_TAB_ADDON_TYPE, index,
437				reinterpret_cast<void**>(&addon)) == B_OK; index++) {
438		if(!addon)
439			continue;
440
441		int32 insertIndex = 0;
442		for(; insertIndex < addons.CountItems(); insertIndex++)
443			if(addons.ItemAt(insertIndex)->Priority() <= addon->Priority())
444				break;
445
446		addons.AddItem(addon, insertIndex);
447	}
448
449	settings->AddInt32("Interface", static_cast<int32>(fWatching));
450	if(fCurrentItem)
451		settings->AddString("InterfaceName", fCurrentItem->Label());
452
453	for(int32 index = 0; index < addons.CountItems(); index++)
454		if(!addons.ItemAt(index)->SaveSettings(settings, profile, saveTemporary))
455			return false;
456
457	return true;
458}
459
460
461bool
462DialUpView::SaveSettingsToFile()
463{
464	bool settingsChanged, profileChanged;
465	IsModified(&settingsChanged, &profileChanged);
466	if(!settingsChanged && !profileChanged)
467		return true;
468
469	BMessage settings, profile;
470	if(!SaveSettings(&settings, &profile, false))
471		return false;
472
473	BDirectory settingsDirectory;
474	BDirectory profileDirectory;
475	GetPPPDirectories(&settingsDirectory, &profileDirectory);
476	if(settingsDirectory.InitCheck() != B_OK || profileDirectory.InitCheck() != B_OK)
477		return false;
478
479	BFile file;
480	if(settingsChanged) {
481		settingsDirectory.CreateFile(fCurrentItem->Label(), &file);
482		WriteMessageDriverSettings(file, settings);
483	}
484
485	if(profileChanged) {
486		profileDirectory.CreateFile(fCurrentItem->Label(), &file);
487		WriteMessageDriverSettings(file, profile);
488	}
489
490	return true;
491}
492
493
494void
495DialUpView::UpDownThread()
496{
497	SaveSettingsToFile();
498	BMessage settings, profile;
499	SaveSettings(&settings, &profile, true);
500		// save temporary profile
501	driver_settings *temporaryProfile = MessageToDriverSettings(profile);
502
503	PPPInterface interface;
504	if(fWatching == PPP_UNDEFINED_INTERFACE_ID) {
505		interface = fListener.Manager().InterfaceWithName(fCurrentItem->Label());
506		if(interface.InitCheck() != B_OK)
507			interface = fListener.Manager().CreateInterfaceWithName(
508				fCurrentItem->Label(), temporaryProfile);
509	} else {
510		interface = fWatching;
511		interface.SetProfile(temporaryProfile);
512	}
513
514	free_driver_settings(temporaryProfile);
515
516	if(interface.InitCheck() != B_OK) {
517		Window()->Lock();
518		fStatusView->SetText(kTextCreationError);
519		Window()->Unlock();
520		return;
521	}
522
523	ppp_interface_info_t info;
524	interface.GetInterfaceInfo(&info);
525	if(info.info.phase == PPP_DOWN_PHASE)
526		interface.Up();
527	else
528		interface.Down();
529
530	fUpDownThread = -1;
531}
532
533
534void
535DialUpView::GetPPPDirectories(BDirectory *settingsDirectory,
536	BDirectory *profileDirectory) const
537{
538	if(settingsDirectory) {
539		BDirectory settings(PPP_INTERFACE_SETTINGS_PATH);
540		if(settings.InitCheck() != B_OK) {
541			create_directory(PPP_INTERFACE_SETTINGS_PATH, 0750);
542			settings.SetTo(PPP_INTERFACE_SETTINGS_PATH);
543		}
544
545		*settingsDirectory = settings;
546	}
547
548	if(profileDirectory) {
549		BDirectory profile(PPP_INTERFACE_SETTINGS_PATH "/profile");
550		if(profile.InitCheck() != B_OK) {
551			create_directory(PPP_INTERFACE_SETTINGS_PATH "/profile", 0750);
552			profile.SetTo(PPP_INTERFACE_SETTINGS_PATH "/profile");
553		}
554
555		*profileDirectory = profile;
556	}
557}
558
559
560void
561DialUpView::HandleReportMessage(BMessage *message)
562{
563	thread_id sender;
564	message->FindInt32("sender", &sender);
565
566	send_data(sender, B_OK, NULL, 0);
567
568	if(!fCurrentItem)
569		return;
570
571	ppp_interface_id id;
572	if(message->FindInt32("interface", reinterpret_cast<int32*>(&id)) != B_OK
573			|| (fWatching != PPP_UNDEFINED_INTERFACE_ID && id != fWatching))
574		return;
575
576	int32 type, code;
577	message->FindInt32("type", &type);
578	message->FindInt32("code", &code);
579
580	if(type == PPP_MANAGER_REPORT && code == PPP_REPORT_INTERFACE_CREATED) {
581		PPPInterface interface(id);
582		if(interface.InitCheck() != B_OK)
583			return;
584
585		ppp_interface_info_t info;
586		interface.GetInterfaceInfo(&info);
587		if(strcasecmp(info.info.name, fCurrentItem->Label()))
588			return;
589
590		WatchInterface(id);
591	} else if(type == PPP_CONNECTION_REPORT) {
592		if(fWatching == PPP_UNDEFINED_INTERFACE_ID)
593			return;
594
595		UpdateStatus(code);
596	} else if(type == PPP_DESTRUCTION_REPORT) {
597		if(fWatching == PPP_UNDEFINED_INTERFACE_ID)
598			return;
599
600		WatchInterface(fListener.Manager().InterfaceWithName(fCurrentItem->Label()));
601	}
602}
603
604
605void
606DialUpView::CreateTabs()
607{
608	// create tabs for all registered and valid tab add-ons
609	DialUpAddon *addon;
610	BView *target;
611	float width, height;
612	TemplateList<DialUpAddon*> addons;
613
614	for(int32 index = 0;
615			fAddons.FindPointer(DUN_TAB_ADDON_TYPE, index,
616				reinterpret_cast<void**>(&addon)) == B_OK;
617			index++) {
618		if(!addon || addon->Position() < 0)
619			continue;
620
621		int32 insertIndex = 0;
622		for(; insertIndex < addons.CountItems(); insertIndex++)
623			if(addons.ItemAt(insertIndex)->Position() > addon->Position())
624				break;
625
626		addons.AddItem(addon, insertIndex);
627	}
628
629	for(int32 index = 0; index < addons.CountItems(); index++) {
630		addon = addons.ItemAt(index);
631
632		if(!addon->GetPreferredSize(&width, &height))
633			continue;
634
635		target = addon->CreateView(BPoint(0, 0));
636		if(!target)
637			continue;
638
639		fTabView->AddTab(target, NULL);
640	}
641}
642
643
644void
645DialUpView::UpdateStatus(int32 code)
646{
647	switch(code) {
648		case PPP_REPORT_UP_ABORTED:
649		case PPP_REPORT_DEVICE_UP_FAILED:
650		case PPP_REPORT_LOCAL_AUTHENTICATION_FAILED:
651		case PPP_REPORT_PEER_AUTHENTICATION_FAILED:
652		case PPP_REPORT_DOWN_SUCCESSFUL:
653		case PPP_REPORT_CONNECTION_LOST: {
654			fConnectButton->SetLabel(kLabelConnect);
655		} break;
656
657		default:
658			fConnectButton->SetLabel(kLabelDisconnect);
659	}
660
661	// maybe the status string must not be changed (codes that set fKeepLabel to false
662	// should still be handled)
663	if(fKeepLabel && code != PPP_REPORT_GOING_UP && code != PPP_REPORT_UP_SUCCESSFUL)
664		return;
665
666	if(fListener.InitCheck() != B_OK) {
667		fStatusView->SetText(kErrorNoPPPStack);
668		return;
669	}
670
671	// only errors should set fKeepLabel to true
672	switch(code) {
673		case PPP_REPORT_GOING_UP:
674			fKeepLabel = false;
675			fStatusView->SetText(kTextConnecting);
676		break;
677
678		case PPP_REPORT_UP_SUCCESSFUL:
679			fKeepLabel = false;
680			fStatusView->SetText(kTextConnectionEstablished);
681		break;
682
683		case PPP_REPORT_UP_ABORTED:
684		case PPP_REPORT_DOWN_SUCCESSFUL:
685			fStatusView->SetText(kTextNotConnected);
686		break;
687
688		case PPP_REPORT_DEVICE_UP_FAILED:
689			fKeepLabel = true;
690			fStatusView->SetText(kTextDeviceUpFailed);
691		break;
692
693		case PPP_REPORT_LOCAL_AUTHENTICATION_REQUESTED:
694		case PPP_REPORT_PEER_AUTHENTICATION_REQUESTED:
695			fStatusView->SetText(kTextAuthenticating);
696		break;
697
698		case PPP_REPORT_LOCAL_AUTHENTICATION_FAILED:
699		case PPP_REPORT_PEER_AUTHENTICATION_FAILED:
700			fKeepLabel = true;
701			fStatusView->SetText(kTextAuthenticationFailed);
702		break;
703
704		case PPP_REPORT_CONNECTION_LOST:
705			fKeepLabel = true;
706			fStatusView->SetText(kTextConnectionLost);
707		break;
708	}
709}
710
711
712void
713DialUpView::WatchInterface(ppp_interface_id ID)
714{
715	// This method can be used to update the interface's connection status.
716
717	if(fWatching != ID) {
718		fListener.StopWatchingInterfaces();
719
720		if(ID == PPP_UNDEFINED_INTERFACE_ID || fListener.WatchInterface(ID))
721			fWatching = ID;
722	}
723
724	// update status
725	PPPInterface interface(fWatching);
726	if(interface.InitCheck() != B_OK) {
727		UpdateStatus(PPP_REPORT_DOWN_SUCCESSFUL);
728		return;
729	}
730
731	ppp_interface_info_t info;
732	interface.GetInterfaceInfo(&info);
733
734	// transform phase into status
735	switch(info.info.phase) {
736		case PPP_DOWN_PHASE:
737			UpdateStatus(PPP_REPORT_DOWN_SUCCESSFUL);
738		break;
739
740		case PPP_TERMINATION_PHASE:
741		break;
742
743		case PPP_ESTABLISHED_PHASE:
744			UpdateStatus(PPP_REPORT_UP_SUCCESSFUL);
745		break;
746
747		default:
748			UpdateStatus(PPP_REPORT_GOING_UP);
749	}
750}
751
752
753void
754DialUpView::LoadInterfaces()
755{
756	fInterfaceMenu->AddSeparatorItem();
757	fInterfaceMenu->AddItem(new BMenuItem(kLabelCreateNewInterface,
758		new BMessage(kMsgCreateNew)));
759	fDeleterItem = new BMenuItem(kLabelDeleteCurrent,
760		new BMessage(kMsgDeleteCurrent));
761	fInterfaceMenu->AddItem(fDeleterItem);
762
763	BDirectory settingsDirectory;
764	BEntry entry;
765	BPath path;
766	GetPPPDirectories(&settingsDirectory, NULL);
767	while(settingsDirectory.GetNextEntry(&entry) == B_OK) {
768		if(entry.IsFile()) {
769			entry.GetPath(&path);
770			AddInterface(path.Leaf(), true);
771		}
772	}
773}
774
775
776void
777DialUpView::LoadAddons()
778{
779	// Load integrated add-ons:
780	// "Connection Options" tab
781	ConnectionOptionsAddon *connectionOptionsAddon =
782		new ConnectionOptionsAddon(&fAddons);
783	fAddons.AddPointer(DUN_TAB_ADDON_TYPE, connectionOptionsAddon);
784	fAddons.AddPointer(DUN_DELETE_ON_QUIT, connectionOptionsAddon);
785	// "General" tab
786	GeneralAddon *fGeneralAddon = new GeneralAddon(&fAddons);
787	fAddons.AddPointer(DUN_TAB_ADDON_TYPE, fGeneralAddon);
788	fAddons.AddPointer(DUN_DELETE_ON_QUIT, fGeneralAddon);
789/*
790	// "IPCP" protocol
791	IPCPAddon *ipcpAddon = new IPCPAddon(&fAddons);
792	fAddons.AddPointer(DUN_TAB_ADDON_TYPE, ipcpAddon);
793	fAddons.AddPointer(DUN_DELETE_ON_QUIT, ipcpAddon);
794	// "PPPoE" device
795	PPPoEAddon *pppoeAddon = new PPPoEAddon(&fAddons);
796	fAddons.AddPointer(DUN_DEVICE_ADDON_TYPE, pppoeAddon);
797	fAddons.AddPointer(DUN_DELETE_ON_QUIT, pppoeAddon);
798*/
799	// "PAP" authenticator
800	BMessage addon;
801#ifdef LANG_GERMAN
802	addon.AddString("FriendlyName", "Unverschl��sselt");
803#else
804	addon.AddString("FriendlyName", "Plain-text Authentication");
805#endif
806	addon.AddString("TechnicalName", "PAP");
807	addon.AddString("KernelModuleName", "pap");
808	fAddons.AddMessage(DUN_AUTHENTICATOR_ADDON_TYPE, &addon);
809	// addon.MakeEmpty(); // for next authenticator
810
811	// TODO:
812	// load all add-ons from the add-ons folder
813}
814
815
816void
817DialUpView::AddInterface(const char *name, bool isNew)
818{
819	if(fInterfaceMenu->FindItem(name)) {
820		(new BAlert(kErrorTitle, kErrorInterfaceExists, kLabelOK,
821			NULL, NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(NULL);
822		return;
823	}
824
825	BMenuItem *item = new BMenuItem(name, new BMessage(kMsgSelectInterface));
826	item->SetTarget(this);
827	int32 index = FindNextMenuInsertionIndex(fInterfaceMenu, name);
828	if(index > CountInterfaces())
829		index = CountInterfaces();
830	fInterfaceMenu->AddItem(item, index);
831	UpdateControls();
832
833	item->SetMarked(true);
834	SelectInterface(index, isNew);
835}
836
837
838void
839DialUpView::SelectInterface(int32 index, bool isNew)
840{
841	BMenuItem *item = fInterfaceMenu->FindMarked();
842	if(fCurrentItem && item == fCurrentItem)
843		return;
844
845	if(fCurrentItem && !SaveSettingsToFile())
846		(new BAlert(kErrorTitle, kErrorSavingFailed, kLabelOK,
847			NULL, NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(NULL);
848
849	if(index >= CountInterfaces() || index < 0) {
850		if(CountInterfaces() > 0)
851			SelectInterface(0);
852		else {
853			fCurrentItem = NULL;
854			WatchInterface(PPP_UNDEFINED_INTERFACE_ID);
855		}
856	} else {
857		fCurrentItem = fInterfaceMenu->ItemAt(index);
858		if(!fCurrentItem) {
859			SelectInterface(0);
860			return;
861		}
862
863		fCurrentItem->SetMarked(true);
864		fDeleterItem->SetEnabled(true);
865		WatchInterface(fListener.Manager().InterfaceWithName(fCurrentItem->Label()));
866	}
867
868	if(!fCurrentItem)
869		LoadSettings(false);
870			// tell modules to unload all settings
871	else if(!isNew && !LoadSettings(false)) {
872		(new BAlert(kErrorTitle, kErrorLoadingFailed, kLabelOK,
873			NULL, NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(NULL);
874		LoadSettings(true);
875	} else if(isNew && !LoadSettings(true))
876		(new BAlert(kErrorTitle, kErrorLoadingFailed, kLabelOK,
877			NULL, NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(NULL);
878}
879
880
881int32
882DialUpView::CountInterfaces() const
883{
884	return fInterfaceMenu->CountItems() - 3;
885}
886
887
888void
889DialUpView::UpdateControls()
890{
891	if(fTabView->IsHidden() && CountInterfaces() > 0) {
892		fInterfaceMenu->SetLabelFromMarked(true);
893		fStringView->Hide();
894		fCreateNewButton->Hide();
895		fTabView->Show();
896		fConnectButton->SetEnabled(true);
897	} else if(!fTabView->IsHidden() && CountInterfaces() == 0) {
898		fDeleterItem->SetEnabled(false);
899		fInterfaceMenu->SetRadioMode(false);
900		fInterfaceMenu->Superitem()->SetLabel(kLabelCreateNew);
901		fTabView->Hide();
902		fStringView->Show();
903		fCreateNewButton->Show();
904		fConnectButton->SetEnabled(false);
905	}
906}
907