xref: /haiku/src/add-ons/network_settings/dialup/GeneralAddon.cpp (revision 02354704729d38c3b078c696adc1bbbd33cbcf72)
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 // GeneralAddon saves the loaded settings.
9 // GeneralView saves the current settings.
10 //-----------------------------------------------------------------------
11 
12 #include "GeneralAddon.h"
13 
14 #include "InterfaceUtils.h"
15 #include "MessageDriverSettingsUtils.h"
16 
17 #include <Box.h>
18 #include <Button.h>
19 #include <MenuField.h>
20 #include <MenuItem.h>
21 #include <LayoutBuilder.h>
22 #include <PopUpMenu.h>
23 #include <StringView.h>
24 
25 #include <PPPDefs.h>
26 
27 
28 // message constants
29 static const uint32 kMsgSelectDevice = 'SELD';
30 static const uint32 kMsgSelectAuthenticator = 'SELA';
31 
32 // labels
33 static const char *kLabelGeneral = "General";
34 static const char *kLabelDevice = "Device: ";
35 static const char *kLabelNoDevicesFound = "No Devices Found!";
36 static const char *kLabelAuthenticator = "Login: ";
37 static const char *kLabelNoAuthenticatorsFound = "No Authenticators Found!";
38 static const char *kLabelName = "Username: ";
39 static const char *kLabelPassword = "Password: ";
40 static const char *kLabelSavePassword = "Save Password";
41 static const char *kLabelNone = "None";
42 
43 // string constants for information saved in the settings message
44 static const char *kGeneralTabAuthentication = "Authentication";
45 static const char *kGeneralTabAuthenticators = "Authenticators";
46 
47 
48 #define DEFAULT_AUTHENTICATOR		"PAP"
49 	// this authenticator is selected by default when creating a new interface
50 
51 
52 GeneralAddon::GeneralAddon(BMessage *addons)
53 	: DialUpAddon(addons),
54 	fHasPassword(false),
55 	fAuthenticatorsCount(0),
56 	fSettings(NULL),
57 	fProfile(NULL),
58 	fGeneralView(NULL)
59 {
60 }
61 
62 
63 GeneralAddon::~GeneralAddon()
64 {
65 }
66 
67 
68 bool
69 GeneralAddon::NeedsAuthenticationRequest() const
70 {
71 	return fGeneralView->AuthenticatorName();
72 }
73 
74 
75 DialUpAddon*
76 GeneralAddon::FindDevice(const BString& moduleName) const
77 {
78 	DialUpAddon *addon;
79 	for(int32 index = 0; Addons()->FindPointer(DUN_DEVICE_ADDON_TYPE, index,
80 			reinterpret_cast<void**>(&addon)) == B_OK; index++)
81 		if(addon && moduleName == addon->KernelModuleName())
82 			return addon;
83 
84 	return NULL;
85 }
86 
87 
88 bool
89 GeneralAddon::LoadSettings(BMessage *settings, BMessage *profile, bool isNew)
90 {
91 	fIsNew = isNew;
92 	fHasPassword = false;
93 	fDeviceName = fUsername = fPassword = "";
94 	fDeviceAddon = NULL;
95 	fAuthenticatorsCount = 0;
96 	fSettings = settings;
97 	fProfile = profile;
98 
99 	if(fGeneralView)
100 		fGeneralView->Reload();
101 			// reset all views (empty settings)
102 
103 	if(!settings || !profile || isNew)
104 		return true;
105 
106 	if(!LoadDeviceSettings())
107 		return false;
108 
109 	if(!LoadAuthenticationSettings())
110 		return false;
111 
112 	if(fGeneralView)
113 		fGeneralView->Reload();
114 			// reload new settings
115 
116 	return true;
117 }
118 
119 
120 bool
121 GeneralAddon::LoadDeviceSettings()
122 {
123 	int32 index = 0;
124 	BMessage device;
125 	if(!FindMessageParameter(PPP_DEVICE_KEY, *fSettings, &device, &index))
126 		return false;
127 			// TODO: tell user that device specification is missing
128 
129 	if(device.FindString(MDSU_VALUES, &fDeviceName) != B_OK)
130 		return false;
131 			// TODO: tell user that device specification is missing
132 
133 	device.AddBool(MDSU_VALID, true);
134 	fSettings->ReplaceMessage(MDSU_PARAMETERS, index, &device);
135 
136 	fDeviceAddon = FindDevice(fDeviceName);
137 	if(!fDeviceAddon)
138 		return false;
139 
140 	return fDeviceAddon->LoadSettings(fSettings, fProfile, false);
141 }
142 
143 
144 bool
145 GeneralAddon::LoadAuthenticationSettings()
146 {
147 	// we only handle the profile (although settings could contain different data)
148 	int32 itemIndex = 0;
149 	BMessage authentication, item;
150 
151 	if(!FindMessageParameter(PPP_AUTHENTICATOR_KEY, *fProfile, &item, &itemIndex))
152 		return true;
153 
154 	// find authenticators (though we load all authenticators, we only use one)
155 	BString name;
156 	for(int32 index = 0; item.FindString(MDSU_VALUES, index, &name) == B_OK; index++) {
157 		BMessage authenticator;
158 		if(!GetAuthenticator(name, &authenticator))
159 			return false;
160 				// fatal error: we do not know how to handle this authenticator
161 
162 		MarkAuthenticatorAsValid(name);
163 		authentication.AddString(kGeneralTabAuthenticators, name);
164 		++fAuthenticatorsCount;
165 	}
166 
167 	fSettings->AddMessage(kGeneralTabAuthentication, &authentication);
168 
169 	bool hasUsername = false;
170 		// a username must be present
171 
172 	// load username and password
173 	BMessage parameter;
174 	int32 parameterIndex = 0;
175 	if(FindMessageParameter("User", item, &parameter, &parameterIndex)
176 			&& parameter.FindString(MDSU_VALUES, &fUsername) == B_OK) {
177 		hasUsername = true;
178 		parameter.AddBool(MDSU_VALID, true);
179 		item.ReplaceMessage(MDSU_PARAMETERS, parameterIndex, &parameter);
180 	}
181 
182 	parameterIndex = 0;
183 	if(FindMessageParameter("Password", item, &parameter, &parameterIndex)
184 			&& parameter.FindString(MDSU_VALUES, &fPassword) == B_OK) {
185 		fHasPassword = true;
186 		parameter.AddBool(MDSU_VALID, true);
187 		item.ReplaceMessage(MDSU_PARAMETERS, parameterIndex, &parameter);
188 	}
189 
190 	// tell DUN whether everything is valid
191 	if(hasUsername)
192 		item.AddBool(MDSU_VALID, true);
193 
194 	fProfile->ReplaceMessage(MDSU_PARAMETERS, itemIndex, &item);
195 
196 	return true;
197 }
198 
199 
200 bool
201 GeneralAddon::HasTemporaryProfile() const
202 {
203 	return fGeneralView->HasTemporaryProfile();
204 }
205 
206 
207 void
208 GeneralAddon::IsModified(bool *settings, bool *profile) const
209 {
210 	if(!fSettings) {
211 		*settings = *profile = false;
212 		return;
213 	}
214 
215 	bool deviceSettings, authenticationSettings, deviceProfile, authenticationProfile;
216 
217 	IsDeviceModified(&deviceSettings, &deviceProfile);
218 	IsAuthenticationModified(&authenticationSettings, &authenticationProfile);
219 
220 	*settings = (deviceSettings || authenticationSettings);
221 	*profile = (deviceProfile || authenticationProfile);
222 }
223 
224 
225 void
226 GeneralAddon::IsDeviceModified(bool *settings, bool *profile) const
227 {
228 	fGeneralView->IsDeviceModified(settings, profile);
229 }
230 
231 
232 void
233 GeneralAddon::IsAuthenticationModified(bool *settings, bool *profile) const
234 {
235 	// currently we only support selecting one authenticator
236 	if(fAuthenticatorsCount == 0)
237 		*settings = fGeneralView->AuthenticatorName();
238 	else {
239 		BMessage authentication;
240 		if(fSettings->FindMessage(kGeneralTabAuthentication, &authentication) != B_OK) {
241 			*settings = *profile = false;
242 			return;
243 				// error!
244 		}
245 
246 		BString authenticator;
247 		if(authentication.FindString(kGeneralTabAuthenticators,
248 				&authenticator) != B_OK) {
249 			*settings = *profile = false;
250 			return;
251 				// error!
252 		}
253 
254 		*settings = (!fGeneralView->AuthenticatorName()
255 			|| authenticator != fGeneralView->AuthenticatorName());
256 	}
257 
258 	*profile = (*settings || fUsername != fGeneralView->Username()
259 		|| (fPassword != fGeneralView->Password() && fHasPassword)
260 		|| fHasPassword != fGeneralView->DoesSavePassword());
261 }
262 
263 
264 bool
265 GeneralAddon::SaveSettings(BMessage *settings, BMessage *profile, bool saveTemporary)
266 {
267 	if(!fSettings || !settings || !fGeneralView->DeviceName())
268 		return false;
269 			// TODO: tell user that a device is needed (if we fail because of this)
270 
271 	if(!fGeneralView->DeviceAddon() || !fGeneralView->DeviceAddon()->SaveSettings(
272 			settings, profile, saveTemporary))
273 		return false;
274 
275 	if(fGeneralView->AuthenticatorName()) {
276 		BMessage authenticator;
277 		authenticator.AddString(MDSU_NAME, PPP_AUTHENTICATOR_KEY);
278 		authenticator.AddString(MDSU_VALUES, fGeneralView->AuthenticatorName());
279 		settings->AddMessage(MDSU_PARAMETERS, &authenticator);
280 
281 		BMessage username;
282 		username.AddString(MDSU_NAME, "User");
283 		username.AddString(MDSU_VALUES, fGeneralView->Username());
284 		authenticator.AddMessage(MDSU_PARAMETERS, &username);
285 
286 		if(saveTemporary || fGeneralView->DoesSavePassword()) {
287 			// save password, too
288 			BMessage password;
289 			password.AddString(MDSU_NAME, "Password");
290 			password.AddString(MDSU_VALUES, fGeneralView->Password());
291 			authenticator.AddMessage(MDSU_PARAMETERS, &password);
292 		}
293 
294 		profile->AddMessage(MDSU_PARAMETERS, &authenticator);
295 	}
296 
297 	return true;
298 }
299 
300 
301 bool
302 GeneralAddon::GetPreferredSize(float *width, float *height) const
303 {
304 	BRect rect;
305 	if(Addons()->FindRect(DUN_TAB_VIEW_RECT, &rect) != B_OK)
306 		rect.Set(0, 0, 200, 300);
307 			// set default values
308 
309 	if(width)
310 		*width = rect.Width();
311 	if(height)
312 		*height = rect.Height();
313 
314 	return true;
315 }
316 
317 
318 BView*
319 GeneralAddon::CreateView()
320 {
321 	if (!fGeneralView) {
322 		fGeneralView = new GeneralView(this);
323 		fGeneralView->Reload();
324 	}
325 
326 	return fGeneralView;
327 }
328 
329 
330 bool
331 GeneralAddon::GetAuthenticator(const BString& moduleName, BMessage *entry) const
332 {
333 	if(!entry)
334 		return false;
335 
336 	BString name;
337 	for(int32 index = 0; Addons()->FindMessage(DUN_AUTHENTICATOR_ADDON_TYPE, index,
338 			entry) == B_OK; index++) {
339 		entry->FindString("KernelModuleName", &name);
340 		if (name == moduleName)
341 			return true;
342 	}
343 
344 	return false;
345 }
346 
347 
348 bool
349 GeneralAddon::MarkAuthenticatorAsValid(const BString& moduleName)
350 {
351 	BMessage authenticator;
352 	int32 index = 0;
353 	BString name;
354 
355 	for(; FindMessageParameter(PPP_AUTHENTICATOR_KEY, *fSettings, &authenticator,
356 			&index); index++) {
357 		authenticator.FindString("KernelModuleName", &name);
358 		if(name == moduleName) {
359 			authenticator.AddBool(MDSU_VALID, true);
360 			fSettings->ReplaceMessage(MDSU_PARAMETERS, index, &authenticator);
361 			return true;
362 		}
363 	}
364 
365 	return false;
366 }
367 
368 
369 GeneralView::GeneralView(GeneralAddon *addon)
370 	: BView(kLabelGeneral, 0),
371 	fAddon(addon)
372 {
373 	fDeviceBox = new BBox("Device");
374 	Addon()->Addons()->AddFloat(DUN_DEVICE_VIEW_WIDTH,
375 		fDeviceBox->Bounds().Width() - 10); // FIXME: remove
376 
377 	fDeviceField = new BMenuField("Device",
378 		kLabelDevice, new BPopUpMenu(kLabelNoDevicesFound));
379 	fDeviceField->Menu()->SetRadioMode(true);
380 	AddDevices();
381 	fDeviceBox->SetLabel(fDeviceField);
382 
383 	fAuthenticatorField = new BMenuField("Authenticator",
384 		kLabelAuthenticator, new BPopUpMenu(kLabelNoAuthenticatorsFound));
385 	fAuthenticatorField->Menu()->SetRadioMode(true);
386 	AddAuthenticators();
387 
388 	fUsername = new BTextControl("username", kLabelName, NULL, NULL);
389 	fPassword = new BTextControl("password", kLabelPassword, NULL, NULL);
390 	fPassword->TextView()->HideTyping(true);
391 
392 	fSavePassword = new BCheckBox("SavePassword", kLabelSavePassword, NULL);
393 
394 	BLayoutBuilder::Group<>(this, B_VERTICAL, B_USE_HALF_ITEM_SPACING)
395 		.SetInsets(B_USE_HALF_ITEM_INSETS)
396 		.AddGroup(B_HORIZONTAL)
397 			.Add(fDeviceBox)
398 			.AddGlue()
399 		.End()
400 		.Add(fAuthenticatorField)
401 		.Add(fUsername)
402 		.Add(fPassword)
403 		.Add(fSavePassword)
404 		.AddGlue()
405 	.End();
406 }
407 
408 
409 GeneralView::~GeneralView()
410 {
411 }
412 
413 
414 void
415 GeneralView::Reload()
416 {
417 	fDeviceAddon = NULL;
418 
419 	BMenuItem *item = NULL;
420 	for(int32 index = 0; index < fDeviceField->Menu()->CountItems(); index++) {
421 		item = fDeviceField->Menu()->ItemAt(index);
422 		if(item && item->Message() && item->Message()->FindPointer("Addon",
423 					reinterpret_cast<void**>(&fDeviceAddon)) == B_OK
424 				&& fDeviceAddon == Addon()->DeviceAddon())
425 			break;
426 	}
427 
428 	if(fDeviceAddon && fDeviceAddon == Addon()->DeviceAddon())
429 		item->SetMarked(true);
430 	else if(Addon()->IsNew() && fDeviceField->Menu()->CountItems() > 0) {
431 		item = fDeviceField->Menu()->ItemAt(0);
432 		item->SetMarked(true);
433 		item->Message()->FindPointer("Addon", reinterpret_cast<void**>(&fDeviceAddon));
434 		fDeviceAddon->LoadSettings(Addon()->Settings(), Addon()->Profile(), true);
435 	} else {
436 		fDeviceAddon = NULL;
437 		item = fDeviceField->Menu()->FindMarked();
438 		if(item)
439 			item->SetMarked(false);
440 	}
441 
442 	if(Addon()->CountAuthenticators() > 0) {
443 		BString kernelModule, authenticator;
444 		BMessage authentication;
445 		if(Addon()->Settings()->FindMessage(kGeneralTabAuthentication,
446 				&authentication) == B_OK)
447 			authentication.FindString(kGeneralTabAuthenticators, &authenticator);
448 		BMenu *menu = fAuthenticatorField->Menu();
449 		for(int32 index = 0; index < menu->CountItems(); index++) {
450 			item = menu->ItemAt(index);
451 			if(item && item->Message()
452 					&& item->Message()->FindString("KernelModuleName",
453 						&kernelModule) == B_OK && kernelModule == authenticator) {
454 				item->SetMarked(true);
455 				break;
456 			}
457 		}
458 	} else if(Addon()->IsNew() && fAuthenticatorDefault)
459 		fAuthenticatorDefault->SetMarked(true);
460 	else
461 		fAuthenticatorNone->SetMarked(true);
462 
463 	fUsername->SetText(Addon()->Username());
464 	fPassword->SetText(Addon()->Password());
465 	fSavePassword->SetValue(Addon()->HasPassword());
466 
467 	ReloadDeviceView();
468 	UpdateControls();
469 }
470 
471 
472 const char*
473 GeneralView::DeviceName() const
474 {
475 	if(fDeviceAddon)
476 		return fDeviceAddon->KernelModuleName();
477 
478 	return NULL;
479 }
480 
481 
482 const char*
483 GeneralView::AuthenticatorName() const
484 {
485 	BMenuItem *marked = fAuthenticatorField->Menu()->FindMarked();
486 	if(marked && marked != fAuthenticatorNone)
487 		return marked->Message()->FindString("KernelModuleName");
488 
489 	return NULL;
490 }
491 
492 
493 void
494 GeneralView::IsDeviceModified(bool *settings, bool *profile) const
495 {
496 	if(fDeviceAddon != Addon()->DeviceAddon())
497 		*settings = *profile = true;
498 	else if(fDeviceAddon)
499 		fDeviceAddon->IsModified(settings, profile);
500 	else
501 		*settings = *profile = false;
502 }
503 
504 
505 void
506 GeneralView::AttachedToWindow()
507 {
508 	SetViewColor(Parent()->ViewColor());
509 	fDeviceField->Menu()->SetTargetForItems(this);
510 	fAuthenticatorField->Menu()->SetTargetForItems(this);
511 	fUsername->SetTarget(this);
512 	fPassword->SetTarget(this);
513 }
514 
515 
516 void
517 GeneralView::MessageReceived(BMessage *message)
518 {
519 	switch(message->what) {
520 		case kMsgSelectDevice:
521 			if(message->FindPointer("Addon", reinterpret_cast<void**>(&fDeviceAddon))
522 					!= B_OK)
523 				fDeviceAddon = NULL;
524 			else {
525 				if(fDeviceAddon != Addon()->DeviceAddon())
526 					fDeviceAddon->LoadSettings(Addon()->Settings(), Addon()->Profile(),
527 						Addon()->IsNew());
528 
529 				ReloadDeviceView();
530 			}
531 		break;
532 
533 		case kMsgSelectAuthenticator:
534 			UpdateControls();
535 		break;
536 
537 		default:
538 			BView::MessageReceived(message);
539 	}
540 }
541 
542 
543 void
544 GeneralView::ReloadDeviceView()
545 {
546 	// first remove existing device view(s)
547 	while (fDeviceBox->CountChildren() > 1)
548 		fDeviceBox->RemoveChild(fDeviceBox->ChildAt(1));
549 
550 	if (!fDeviceAddon)
551 		return;
552 
553 	BView* deviceView = fDeviceAddon->CreateView();
554 	if (deviceView) {
555 		BLayoutBuilder::Group<>(fDeviceBox, B_VERTICAL)
556 			.Add(deviceView)
557 		.End();
558 	}
559 }
560 
561 
562 void
563 GeneralView::UpdateControls()
564 {
565 	BMenu *menu = fAuthenticatorField->Menu();
566 	int32 index = menu->IndexOf(menu->FindMarked());
567 	if (index < 0)
568 		fAuthenticatorNone->SetMarked(true);
569 
570 	if (index == 0) {
571 		fUsername->SetEnabled(false);
572 		fPassword->SetEnabled(false);
573 		fSavePassword->SetEnabled(false);
574 	} else {
575 		fUsername->SetEnabled(true);
576 		fPassword->SetEnabled(true);
577 		fSavePassword->SetEnabled(true);
578 	}
579 }
580 
581 
582 void
583 GeneralView::AddDevices()
584 {
585 	AddAddonsToMenu(Addon()->Addons(), fDeviceField->Menu(), DUN_DEVICE_ADDON_TYPE,
586 		kMsgSelectDevice);
587 }
588 
589 
590 void
591 GeneralView::AddAuthenticators()
592 {
593 	fAuthenticatorDefault = NULL;
594 	fAuthenticatorNone = new BMenuItem(kLabelNone,
595 		new BMessage(kMsgSelectAuthenticator));
596 	fAuthenticatorField->Menu()->AddItem(fAuthenticatorNone);
597 	fAuthenticatorNone->SetMarked(true);
598 	fAuthenticatorField->Menu()->AddSeparatorItem();
599 
600 	BMenuItem *item;
601 	BMessage addon;
602 	for(int32 index = 0;
603 			Addon()->Addons()->FindMessage(DUN_AUTHENTICATOR_ADDON_TYPE, index,
604 			&addon) == B_OK; index++) {
605 		BMessage *message = new BMessage(kMsgSelectAuthenticator);
606 		message->AddString("KernelModuleName", addon.FindString("KernelModuleName"));
607 
608 		BString name, technicalName, friendlyName;
609 		bool hasTechnicalName
610 			= (addon.FindString("TechnicalName", &technicalName) == B_OK);
611 		bool hasFriendlyName
612 			= (addon.FindString("FriendlyName", &friendlyName) == B_OK);
613 		if(hasTechnicalName) {
614 			name << technicalName;
615 			if(hasFriendlyName)
616 				name << " (";
617 		}
618 		if(hasFriendlyName) {
619 			name << friendlyName;
620 			if(hasTechnicalName)
621 				name << ")";
622 		}
623 
624 		int32 insertAt = FindNextMenuInsertionIndex(fAuthenticatorField->Menu(),
625 			name.String(), 2);
626 		item = new BMenuItem(name.String(), message);
627 		if(hasTechnicalName && technicalName == DEFAULT_AUTHENTICATOR)
628 			fAuthenticatorDefault = item;
629 		fAuthenticatorField->Menu()->AddItem(item, insertAt);
630 	}
631 }
632