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