xref: /haiku/src/add-ons/network_settings/dialup/DialUpView.cpp (revision 68ea01249e1e2088933cb12f9c28d4e5c5d1c9ef)
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
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';
50 
51 // labels
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";
60 
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 "
72 											"interface.";
73 
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 "
78 										"already exists!";
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!";
82 
83 
84 static
85 status_t
86 up_down_thread(void *data)
87 {
88 	static_cast<DialUpView*>(data)->UpDownThread();
89 	return B_OK;
90 }
91 
92 
93 DialUpView::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 
152 DialUpView::~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 
169 void
170 DialUpView::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 
184 void
185 DialUpView::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 
256 bool
257 DialUpView::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 
271 bool
272 DialUpView::NeedsRequest() const
273 {
274 	return fGeneralAddon ? fGeneralAddon->NeedsAuthenticationRequest() : false;
275 }
276 
277 
278 BView*
279 DialUpView::StatusView() const
280 {
281 	return fStatusView;
282 }
283 
284 
285 BView*
286 DialUpView::ConnectButton() const
287 {
288 	return fConnectButton;
289 }
290 
291 
292 bool
293 DialUpView::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 
327 void
328 DialUpView::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 
349 bool
350 DialUpView::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 
383 bool
384 DialUpView::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 
416 void
417 DialUpView::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!
457 void
458 DialUpView::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 
483 void
484 DialUpView::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 
528 void
529 DialUpView::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 
564 void
565 DialUpView::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 
627 void
628 DialUpView::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 
668 void
669 DialUpView::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 
691 void
692 DialUpView::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 
727 void
728 DialUpView::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 
749 void
750 DialUpView::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 
792 int32
793 DialUpView::CountInterfaces() const
794 {
795 	return fInterfaceMenu->CountItems() - 3;
796 }
797 
798 
799 void
800 DialUpView::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