gecko-dev/cmd/macfe/central/userprofile.cp
1998-06-04 06:57:39 +00:00

2019 lines
53 KiB
C++
Raw Blame History

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "userprofile.h"
#include "client.h"
#include "UStdDialogs.h"
#include "ufilemgr.h"
#include "uerrmgr.h"
#include "uapp.h"
#include "uprefd.h"
#include "prefwutil.h"
#include "macutil.h"
#include "prefapi.h"
#include "resgui.h"
#include "xp_file_mac.h"
#include "DirectoryCopy.h"
// for multi-user profile support in PE
#include "MUC.h"
#include <CodeFragments.h>
#include <LString.h>
#include <LPushButton.h>
#define updateWizardDialog 9800
#define profilePEPane 9801
#define profileIntroPane 9802
#define userNamePane 9803
#define profileNamePane 9804
#define profileFolderPane 9805
#define profileIconsPane 9806
#define profileDonePane 9807
#define profileSelectDialog 9900
#define profileManagerDialog 9901
// NOTE: Magic name must be kept in sync with ns/modules/libreg/src/reg.h
#define MAGIC_PROFILE_NAME "User1"
const char* kProfileNamePref = "profile.name";
/*****************************************************************************
* The resource format for storing profile metadata (i.e., username and
* email) in the profile database so it can be easily searched. In order
* to allow an arbitrary amount of metadata, the resource is divided into
* a header section, which counts the number of metadata items and the length
* to each, and a data section, which simply consists of the data in packed
* format. The offset to each set of data is the sum of the first offset
* plus all of the lengths. Strings are null terminated for convenience.
* All of this is stored in the profile database in a 'DATA' resource
* which corresponds to the id of the profile in use.
****************************************************************************/
/* The version of the metadata for Nav 4.0 */
typedef struct {
short int count;
short int firstOffset;
long int nameLength;
long int emailLength;
/* New data element lengths would go here, along with a corresponding
change in the count and firstOffset items */
/* Data follows here */
} ProfileDataHeader;
MODULE_PRIVATE int PR_CALLBACK ProfilePrefChangedFunc(const char *pref, void *data);
CFragConnectionID CUserProfile::mConfigPluginID;
class LWhiteListBox: public LListBox
{
#if !defined(__MWERKS__) || (__MWERKS__ >= 0x2000)
typedef LListBox inherited;
#endif
public:
enum { class_ID = 'Lwht' };
LWhiteListBox( LStream* inStream );
virtual Boolean FocusDraw(LPane* inSubPane = nil);
virtual void DrawSelf();
};
LWhiteListBox::LWhiteListBox( LStream* inStream ): LListBox( inStream )
{
}
Boolean LWhiteListBox::FocusDraw(LPane* /*inSubPane*/)
{
const RGBColor rgbWhite = { 0xFFFF, 0xFFFF, 0xFFFF };
if ( inherited::FocusDraw() )
{
::RGBBackColor( &rgbWhite );
return TRUE;
}
return FALSE;
}
void LWhiteListBox::DrawSelf()
{
Rect frame;
this->CalcLocalFrameRect( frame );
::EraseRect( &frame );
LListBox::DrawSelf();
}
MODULE_PRIVATE int PR_CALLBACK ProfilePrefChangedFunc(const char *pref, void * /* data */)
{
FSSpec profileSpec = CPrefs::GetFilePrototype(CPrefs::UsersFolder);
GetIndString(profileSpec.name, 300, userProfiles);
CUserProfileDB profile(profileSpec);
if ((!XP_STRCASECMP(pref,"mail.identity.username")) ||
(!XP_STRCASECMP(pref,"mail.identity.useremail")))
{
profile.SetProfileData( CUserProfile::sCurrentProfileID );
}
else if (!XP_STRCMP(pref, kProfileNamePref))
{
char profileName[255];
int len = 255;
if ( PREF_GetCharPref(kProfileNamePref, profileName, &len) == PREF_NOERROR )
{
profile.SetProfileName( CUserProfile::sCurrentProfileID, (CStr255) profileName );
}
}
return 0;
}
class CProfilePaneMonitor : public LListener
{
public:
CProfilePaneMonitor(CDialogWizardHandler*);
virtual void ListenToMessage(MessageT inMessage, void *ioParam);
private:
CDialogWizardHandler* fWizard;
Boolean fCopiedName;
};
/*****************************************************************************
* class CUserProfile
*
* Dialog handlers & wizards for multi-user profile support.
*
*****************************************************************************/
short CUserProfile::sCurrentProfileID = CUserProfile::kInvalidProfileID;
Boolean CUserProfile::mHasConfigPlugin = FALSE;
Boolean CUserProfile::mPluginLoaded = FALSE;
void CUserProfile::InitUserProfiles()
{
mHasConfigPlugin = ( LoadConfigPlugin() != NULL );
if ( mHasConfigPlugin )
CloseConfigPlugin();
}
// Attempts to open "User Profiles" and put up a selection dialog.
// Returns the location of the user's selected Prefs folder.
ProfileErr
CUserProfile::GetUserProfile( const FSSpec& usersFolder, FSSpec& profileFolder,
Boolean showDialog, short fileType )
{
ProfileErr result = eOK;
Boolean done = true;
Boolean wantsProfileManager = showDialog;
FSSpec profileSpec;
short numProfiles = 1;
CStr31 profileName;
// <20><>profileSpec here is "User Profiles"
profileSpec.vRefNum = usersFolder.vRefNum;
profileSpec.parID = usersFolder.parID;
GetIndString( profileSpec.name, 300, userProfiles );
// <20><>I have no idea why this is so convoluted
if ( !CFileMgr::FileExists( profileSpec ) )
return eNeedUpgrade;
if ( DeleteMagicProfile( profileSpec ) )
return eNeedUpgrade;
CUserProfileDB profileDB( profileSpec );
do
{
Try_
{
short newUserID = 0;
short lastUserID = profileDB.GetLastProfileID();
// <20><>only put up dialog if there's more than one user
if ( showDialog || profileDB.CountProfiles() > 1 )
{
// HACK ALERT!!!!!
// If we're being asked to open a doc or get a URL just skip the dialog
// and use the last profile that was selected
if ( (fileType == FILE_TYPE_ODOC) || (fileType == FILE_TYPE_GETURL) )
{
newUserID = lastUserID;
if ( profileDB.GetProfileAlias( newUserID, profileFolder ) )
result = eOK;
else
result = eUnknownError;
}
else
// END HACK ALERT!!!!!
result = HandleProfileDialog(
profileSpec,
profileDB,
profileFolder,
newUserID,
lastUserID,
wantsProfileManager );
if ( result >= 0 && lastUserID != newUserID )
profileDB.SetLastProfileID( newUserID );
if ( result >= eOK )
PREF_RegisterCallback("mail.identity",ProfilePrefChangedFunc, NULL);
done = true;
}
else
{
newUserID = lastUserID;
Try_
{
if ( profileDB.GetProfileAlias( lastUserID, profileFolder ) )
result = eOK;
else
result = eUnknownError;
}
Catch_ ( inErr )
{
CStr255 errStr;
GetIndString( errStr, kProfileStrings, kReadError );
ErrorManager::ErrorNotify( inErr, errStr );
}
if ( result < eOK )
{
// <20> if we failed to load the profile, loop back to the
// beginning and force Profile Manager to appear
done = false;
showDialog = wantsProfileManager = true;
}
else
{
long err;
err = SendMessageToPlugin( kAutoSelectDialConfig, &profileFolder );
if ( err == errProfileNotFound )
SendMessageToPlugin( kEditDialConfig, &profileFolder );
PREF_RegisterCallback( "mail.identity",ProfilePrefChangedFunc, NULL );
}
}
// <20> save the previous user ID back to profile db
if ( result >= eOK )
{
sCurrentProfileID = newUserID;
numProfiles = profileDB.CountProfiles();
}
}
Catch_ ( inErr )
{
CStr255 errStr;
GetIndString( errStr, kProfileStrings, kReadError );
ErrorManager::ErrorNotify( inErr, errStr );
result = eUnknownError;
}
}
while ( !done );
if (result != eUserCancelled) {
// <20><>reflect path & name into xp preferences
if (sCurrentProfileID != kInvalidProfileID)
profileDB.GetProfileName( sCurrentProfileID, profileName );
ReflectToPreferences(profileName, profileFolder, numProfiles);
}
return result;
}
static void PrefToEditField(const char * prefName, LEditField * field);
static void EditFieldToPref(LEditField * field, const char * prefName);
const Uint32 PREF_STRING_LEN = 255;
void PrefToEditField(const char * prefName, LEditField * field)
{
int prefStringLen;
char prefString[PREF_STRING_LEN];
prefStringLen = PREF_STRING_LEN;
if ( PREF_GetCharPref(prefName, prefString, &prefStringLen) == 0 )
{
c2pstr(prefString);
field->SetDescriptor((unsigned char *)prefString);
}
}
void EditFieldToPref(LEditField * field, const char * prefName)
{
Str255 s;
field->GetDescriptor(s);
p2cstr(s);
PREF_SetCharPref(prefName, (char*)s);
}
// Displays the additional data login dialog. Throws are taken care of by
// the caller
void
CUserProfile::DoNetExtendedProfileDialog(LCommander * super)
{
StDialogHandler theHandler(9911, super);
LWindow *theDialog = theHandler.GetDialog();
LEditField *ldapAddressField = dynamic_cast<LEditField*>(theDialog->FindPaneByID('addr'));
LEditField *searchBaseField = dynamic_cast<LEditField*>(theDialog->FindPaneByID('sbas'));
LEditField *httpAddressField = dynamic_cast<LEditField*>(theDialog->FindPaneByID('hurl'));
LControl * ldapRadio = dynamic_cast<LControl*>(theDialog->FindPaneByID('ldap'));
LControl * httpRadio = dynamic_cast<LControl*>(theDialog->FindPaneByID('http'));
ThrowIfNil_(ldapAddressField);
ThrowIfNil_(searchBaseField);
ThrowIfNil_(httpAddressField);
ThrowIfNil_(ldapRadio);
ThrowIfNil_(httpRadio);
// Initialize the dialog from the preferences
// PrefToEditField("li.server.ldap.serverName", ldapAddressField );
// PrefToEditField("li.server.ldap.searchBase", searchBaseField );
// PrefToEditField("li.server.http.baseURL", httpAddressField);
ldapRadio->SetValue(1);
int prefStringLen;
char prefString[PREF_STRING_LEN];
prefStringLen = PREF_STRING_LEN;
if ( PREF_GetCharPref("li.protocol", prefString, &prefStringLen) == 0 )
if (XP_STRCMP(prefString, "http") == 0)
httpRadio->SetValue(1);
// Do the dialog
httpAddressField->SelectAll();
theDialog->SetLatentSub(httpAddressField);
theDialog->Show();
while (true)
{
MessageT hitMessage = theHandler.DoDialog();
if ( hitMessage == msg_Cancel )
break;
else if ( hitMessage == msg_OK )
{
LStr255 httpAddress;
httpAddressField->GetDescriptor(httpAddress);
if ( httpAddress.Length() > 2 )
{
if (!httpAddress.BeginsWith(LStr255("http://")))
httpAddress.Insert(LStr255("http://"), 0);
}
EditFieldToPref(ldapAddressField, "li.server.ldap.serverName");
EditFieldToPref(searchBaseField, "li.server.ldap.searchBase");
EditFieldToPref(httpAddressField, "li.server.http.baseURL");
if ( ldapRadio->GetValue() > 0 )
PREF_SetCharPref("li.protocol", "ldap");
else
PREF_SetCharPref("li.protocol", "http");
break;
}
}
}
// Displays the modal login dialog
ProfileErr
CUserProfile::DoNetProfileDialog()
{
ProfileErr perr = eOK;
try
{
StDialogHandler theHandler(9910, CFrontApp::GetApplication());
LWindow *theDialog = theHandler.GetDialog();
LEditField *usernameField = dynamic_cast<LEditField*>(theDialog->FindPaneByID('user'));
LEditField *passwordField = dynamic_cast<LEditField*>(theDialog->FindPaneByID('pass'));
ThrowIfNil_(usernameField);
ThrowIfNil_(passwordField);
usernameField->SelectAll();
theDialog->SetLatentSub(usernameField);
theDialog->Show();
while (true)
{
MessageT hitMessage = theHandler.DoDialog();
if (hitMessage == msg_Cancel)
{
perr = eUserCancelled;
break;
}
else if (hitMessage == msg_OK)
{
EditFieldToPref( usernameField, "li.login.name");
EditFieldToPref( passwordField, "li.login.password");
PREF_SetBoolPref("li.enabled", true);
perr = eOK;
break;
}
else if (hitMessage == 'adva') // Advanced button
{
DoNetExtendedProfileDialog(theDialog);
}
}
}
catch (ExceptionCode err)
{
XP_ASSERT(false);
perr = eUnknownError;
}
return perr;
}
// Creates a network profile folder
// The folder is located inside the users folder
ProfileErr
CUserProfile::CreateNetProfile( FSSpec usersFolder, FSSpec& profileFolderSpec )
{
ProfileErr perr;
perr = DoNetProfileDialog();
if (perr == eOK)
{
try
{
CStr255 profileFolderName("Temporary Profile");
OSErr err;
// Create the folder spec of the profile directory
profileFolderSpec = usersFolder;
LString::CopyPStr(profileFolderName, profileFolderSpec.name, sizeof(profileFolderSpec.name));
// If the folder already exists, delete it
err = CFileMgr::DeleteFolder( profileFolderSpec );
XP_ASSERT((err == noErr) || (err == fnfErr));
// Create the folder
short dummy;
long dummy2;
err = CFileMgr::CreateFolderInFolder(usersFolder.vRefNum, usersFolder.parID, profileFolderName,
&dummy, &dummy2);
ThrowIfOSErr_(err);
ReflectToPreferences( CStr255("Network Profile"), profileFolderSpec);
}
catch (ExceptionCode err)
{
XP_ASSERT(false);
return eUnknownError;
}
}
return perr;
}
// <20><>launches upgrade wizard for users who have not run 4.0 before
// creates an initial profile folder and User Profiles file.
// if oldNetscapeF is non-null, it points to the user's 3.0
// Netscape <20> folder and the profile "folder" is an alias to it
ProfileErr
CUserProfile::HandleUpgrade( FSSpec& profileFolder, const FSSpec* oldNetscapeF )
{
ProfileErr result = eOK;
CStr31 profileName;
do
{
Try_
{
FSSpec profileSpec = CPrefs::GetFilePrototype( CPrefs::UsersFolder );
if ( mHasConfigPlugin && !oldNetscapeF )
{
profileFolder.vRefNum = profileSpec.vRefNum;
profileFolder.parID = profileSpec.parID;
profileName = MAGIC_PROFILE_NAME;
LString::CopyPStr( profileName, profileFolder.name, 32 );
CreateDefaultProfileFolder( profileFolder );
result = eRunAccountSetup;
}
else
{
UpgradeEnum upgrading = (oldNetscapeF == nil) ? eNewInstall : eExistingPrefs;
result = NewUserProfile( profileSpec, profileFolder, profileName,
upgrading, oldNetscapeF );
}
if ( result == eUserCancelled )
return eUserCancelled;
if ( profileName.Length() == 0 )
GetIndString( profileName, kProfileStrings, kDefaultName );
// <20><>create Profiles file and add the alias
GetIndString( profileSpec.name, 300, userProfiles );
CUserProfileDB profileDB( profileSpec, true );
profileDB.AddNewProfile( 0, profileName, profileFolder );
sCurrentProfileID = 0;
}
Catch_( inErr )
{
CStr255 errStr;
GetIndString( errStr, kProfileStrings, kCreateError );
ErrorManager::ErrorNotify( inErr, errStr );
result = eUnknownError;
// <20><>loop through wizard again if error
// don't loop 5/14/97 tgm
//done = false;
}
}
while ( 0 /*!done*/);
ReflectToPreferences(profileName, profileFolder);
return result;
}
// <20> puts up user-selection dialog and returns selected user ID
ProfileErr CUserProfile::HandleProfileDialog(
FSSpec& profileSpec,
CUserProfileDB& profileDB,
FSSpec& profileFolder,
short& newUserID,
short lastUserID,
Boolean wantsProfileManager )
{
int dialogID = wantsProfileManager ?
profileManagerDialog : profileSelectDialog;
Boolean success = false;
LListBox* listBox;
LPushButton* okButton;
LPane* newButton;
LPane* deleteButton;
LPane* renameButton;
LPane* optionsButton;
ProfileErr result = eOK;
RegisterClass_( LWhiteListBox);
StBlockingDialogHandler dialog( dialogID, CFrontApp::GetApplication() );
listBox = (LListBox*)dialog.GetDialog()->FindPaneByID( 'user' );
ThrowIfNil_( listBox );
ListHandle listHand = listBox->GetMacListH();
(**listHand).selFlags = lOnlyOne + lNoNilHilite; // only one selection
LAddColumn( 1, 0, listHand );
PopulateListBox( listHand, profileDB, lastUserID );
listBox->AddListener( &dialog );
listBox->SwitchTarget( listBox );
okButton = dynamic_cast<LPushButton*>(dialog.GetDialog()->FindPaneByID( 'ok ' ));
deleteButton = dialog.GetDialog()->FindPaneByID( 2 );
renameButton = dialog.GetDialog()->FindPaneByID( 3 );
newButton = dialog.GetDialog()->FindPaneByID( 1 );
optionsButton = dialog.GetDialog()->FindPaneByID( 'Ebut' );
if ( wantsProfileManager )
ThrowIfNil_( okButton && deleteButton && renameButton && newButton );
else
ThrowIfNil_( okButton );
if ( !mHasConfigPlugin )
{
if ( optionsButton )
optionsButton->Hide();
}
else
{
if ( !wantsProfileManager )
SendMessageToPlugin( kInitListener, (LDialogBox*)dialog.GetDialog() );
}
short tempUserID = -1;
/* keep track of the amount of time we've been idly showing this dialog */
long startTime = TickCount();
long elapsedTime = 0;
long secsLeft = 20; //we can also get this from a resource in the User Profiles file if it exists.
Boolean keepCounting = true; // (!wantsProfileManager); /* only countdown in simple profile picker. not manager*/
const ResIDT autoStartResID = 9999;
// Check to see if our secret keep counting resource exists - if not, use default secsLeft
StUseResFile resFile( profileDB.GetFile()->GetResourceForkRefNum() );
StringHandle numSecsStringH = (StringHandle) ::Get1Resource('TEXT', autoStartResID);
if (keepCounting && numSecsStringH)
{
char buffer[4];
buffer[sizeof(buffer)-1] = 0;
memcpy( (unsigned char *)buffer, (unsigned char *)*numSecsStringH, min(GetHandleSize((Handle)numSecsStringH),(long)sizeof(buffer)-1));
secsLeft = atoi(buffer);
if (secsLeft <= 0)
keepCounting = false;
}
while ( !success )
{
//ʥ catch any errors inside dialog loop
Try_
{
Cell cell;
MessageT hit = dialog.DoDialog();
// default to selecting the last selected profile if enough time has elapsed
if (keepCounting && (secsLeft <= 0))
{
okButton->SimulateHotSpotClick(1);
hit = cmd_SelectProfile;
}
else if (keepCounting)
{
// update secsLeft
elapsedTime = TickCount() - startTime;
if (elapsedTime >= 60)
{
secsLeft--;
startTime = TickCount();
}
}
else if (secsLeft >= 0)
secsLeft = -1;
if (listBox->GetLastSelectedCell( cell ) )
{
newUserID = cell.v;
okButton->Enable();
if (wantsProfileManager) {
renameButton->Enable();
if ( profileDB.CountProfiles() > 1 )
// <20><>don't allow deleting last profile
deleteButton->Enable();
else
deleteButton->Disable();
}
if ( optionsButton )
optionsButton->Enable();
}
else
{
newUserID = -1;
okButton->Disable();
if (wantsProfileManager) {
renameButton->Disable();
deleteButton->Disable();
}
if ( optionsButton )
optionsButton->Disable();
}
if ( newUserID != tempUserID )
{
if (tempUserID > -1)
keepCounting = false;
if ( newUserID != -1 && mHasConfigPlugin )
{
if ( profileDB.GetProfileAlias( newUserID, profileFolder, false ) )
SendMessageToPlugin( kNewProfileSelect, &profileFolder );
else
SendMessageToPlugin( kClearProfileSelect, NULL );
}
tempUserID = newUserID;
}
switch ( hit )
{
case cmd_SelectProfile:
success = profileDB.GetProfileAlias( newUserID, profileFolder );
if ( success )
{
long err;
err = SendMessageToPlugin( kSelectDialConfig, &profileFolder );
if ( err == errProfileNotFound )
SendMessageToPlugin( kEditDialConfig, &profileFolder );
}
keepCounting = false;
break;
case cmd_NewProfile:
CStr31 profileName;
result = NewUserProfile( profileSpec, profileFolder, profileName );
if ( result == eUserCancelled )
{
result = eOK;
}
else
{
newUserID = profileDB.CountProfiles();
profileDB.AddNewProfile( newUserID, profileName, profileFolder );
// redraw the profile list box
LDelRow(0, 0, listHand);
PopulateListBox(listHand, profileDB, newUserID);
listBox->Refresh();
success = true;
// <20><>we ran the Profile Wizard and now we should
// open the Edit Settings dialog for the associated
// dial configuration
if ( result == eRunMUC )
{
SendMessageToPlugin( kEditDialConfig, &profileFolder );
result = eOK;
}
// <20> we ran the Profile Wizard, but we don't want to
// associate a dialing configuration, so write out
// an empty "Configuration" file by calling
// the plugin
else if ( result == eSkipMUC )
{
SendMessageToPlugin( kAutoSelectDialConfig, &profileFolder );
result = eOK;
}
}
keepCounting = false;
break;
case cmd_RenameProfile:
RenameProfile( newUserID, profileDB, cell, listHand );
keepCounting = false;
break;
case cmd_DeleteProfile:
DeleteProfile( newUserID, profileDB, listHand );
listBox->Refresh();
keepCounting = false;
break;
case cmd_QuitProfile:
keepCounting = false;
return eUserCancelled;
break;
case cmd_EditDialSettings:
if ( profileDB.GetProfileAlias( newUserID, profileFolder ) )
{
SendMessageToPlugin( kEditDialConfig, &profileFolder );
tempUserID = -1;
}
keepCounting = false;
break;
}
}
Catch_ ( inErr )
{
CStr255 errStr;
GetIndString( errStr, kProfileStrings, kReadError );
ErrorManager::ErrorNotify( inErr, errStr );
}
}
return result;
}
Boolean CUserProfile::DeleteMagicProfile( FSSpec& inSpec )
{
short nextID = 0;
CStr31 profileName;
FSSpec profileSpec;
char* fullURL;
Boolean found = FALSE;
profileSpec.vRefNum = inSpec.vRefNum;
profileSpec.parID = inSpec.parID;
profileName = MAGIC_PROFILE_NAME;
LString::CopyPStr( profileName, profileSpec.name, 32 );
CUserProfileDB db( inSpec );
while ( db.GetProfileName( nextID++, profileName ) )
{
if ( profileName == MAGIC_PROFILE_NAME )
{
db.DeleteProfile( --nextID );
if ( db.GetLastProfileID() == nextID )
db.SetLastProfileID( 0 );
found = TRUE;
break;
}
}
fullURL = CFileMgr::EncodedPathNameFromFSSpec( profileSpec, TRUE );
if ( fullURL && found )
{
XP_RemoveDirectoryRecursive( fullURL, xpURL );
XP_FREE( fullURL );
}
if ( found )
return TRUE;
return FALSE;
}
void CUserProfile::PopulateListBox(ListHandle& listHand, CUserProfileDB& profileDB, short defaultID)
{
LSetDrawingMode(false, listHand);
short nextID = 0;
Cell cell;
CStr31 str;
Boolean gotOne = profileDB.GetProfileName(nextID, str);
while (gotOne) {
LAddRow(1, nextID, listHand);
SetPt(&cell, 0, nextID);
LSetCell(&str.fStr[1], str.fStr[0], cell, listHand);
gotOne = profileDB.GetProfileName(++nextID, str);
}
// <20><>select last user or first cell & scroll to it
SetPt(&cell, 0, defaultID);
LSetSelect(true, cell, listHand);
LAutoScroll(listHand);
LSetDrawingMode(true, listHand);
}
// Ensure the requested new profile folder does not exist;
// if it does, append a number to make a unique name.
void CUserProfile::GetUniqueFolderName(FSSpec& folder)
{
if (CFileMgr::FileExists(folder)) {
int nextIndex = 2;
CStr31 requestedName = folder.name;
if (requestedName.Length() > 28)
requestedName.Length() = 28;
CStr31 uniqueName;
do {
uniqueName = requestedName;
char suffix[3];
sprintf(suffix, "-%d", nextIndex++);
uniqueName += suffix;
LString::CopyPStr(uniqueName, folder.name, 32);
}
while (CFileMgr::FileExists(folder));
}
}
// Make one desktop icon
static const kIconNameStringsListID = 9800;
static OSErr MakeOneDesktopIcon(const CStr31 &profileName, short templateNameIndex, short iconNameIndex)
{
OSErr err = noErr;
FSSpec shortcutSpec = CPrefs::GetFilePrototype(CPrefs::RequiredGutsFolder);
FSSpec desktopFolderSpec;
FSSpec desktopIconSpec;
short vRefNum;
long folderID;
GetIndString(shortcutSpec.name, kIconNameStringsListID, templateNameIndex);
//find the source file
if (!CFileMgr::FileExists(shortcutSpec) || CFileMgr::IsFolder(shortcutSpec))
ThrowIfOSErr_(fnfErr);
//check the destination
err = ::FindFolder(kOnSystemDisk, kDesktopFolderType, true,
&vRefNum, &folderID);
ThrowIfOSErr_(err);
err = CFileMgr::FolderSpecFromFolderID(vRefNum, folderID, desktopFolderSpec);
ThrowIfOSErr_(err);
desktopIconSpec.parID = folderID;
desktopIconSpec.vRefNum = vRefNum;
GetIndString(desktopIconSpec.name, kIconNameStringsListID, iconNameIndex);
//Append the profile name. We know that it does not contain colons
CStr63 iconName(desktopIconSpec.name);
iconName += profileName;
//Truncate the iconName if necessary to 31 chars
if (iconName.Length() > 30) {
iconName[0] = 30;
iconName[30] = '<EFBFBD>';
}
LString::CopyPStr(iconName, desktopIconSpec.name, 31);
//If there is already an icon with the same name, append the profile name
long nextIndex = 1;
while (CFileMgr::FileExists(desktopIconSpec))
{
CStr63 uniqueName(iconName);
char suffix[5];
short len;
sprintf(suffix, "-%d", nextIndex++);
len = 30 - strlen(suffix);
//Truncate the uniqueName if necessary
if (uniqueName.Length() > len) {
uniqueName[0] = len;
uniqueName[len] = '<EFBFBD>';
}
uniqueName += suffix;
LString::CopyPStr(uniqueName, desktopIconSpec.name, 31);
}
//phew. now we have a unique name to copy to
err = CFileMgr::CopyFile(shortcutSpec, desktopFolderSpec, desktopIconSpec.name);
ThrowIfOSErr_(err);
//make sure the custom icon bit is set
err = CFileMgr::SetFileFinderFlag(desktopIconSpec, kHasCustomIcon, TRUE);
ThrowIfOSErr_(err);
//And now copy the profile name into the data fork
if (! CFileMgr::FileExists(desktopIconSpec)) //if it does not, we're in trouble
ThrowIfOSErr_(fnfErr);
LFile scriptFile(desktopIconSpec);
scriptFile.OpenDataFork(fsRdWrPerm);
scriptFile.WriteDataFork((const char*)profileName, profileName.Length());
scriptFile.CloseDataFork();
return err;
}
// Make the desktop icons for the selected profile.
// They are acually applescripts copied from the essential files
// folder, with a property modified for this profile.
OSErr CUserProfile::MakeDesktopIcons(
const CStr31 &profileName,
const Boolean wantsNavigator,
const Boolean wantsInbox )
{
OSErr err = noErr;
enum { kNavShortcutName = 1, kInboxShortcutName,
kNavDesktopName, kInboxDesktopName}; //in profile.cnst
if (wantsNavigator)
err = MakeOneDesktopIcon(profileName, kNavShortcutName, kNavDesktopName);
if (wantsInbox)
err = MakeOneDesktopIcon(profileName, kInboxShortcutName, kInboxDesktopName);
return err;
}
// <20> prompts for a new user profile
ProfileErr CUserProfile::NewUserProfile(
const FSSpec& profileSpec,
FSSpec& profileFolder,
CStr31& profileName,
UpgradeEnum upgrading,
const FSSpec* oldNetscapeF )
{
Boolean userChoseFolder = false;
ProfileErr result = eOK;
profileFolder.vRefNum = profileSpec.vRefNum;
profileFolder.parID = profileSpec.parID;
result = NewProfileWizard( upgrading, profileName, profileSpec,
profileFolder, userChoseFolder );
if ( result == eUserCancelled )
return eUserCancelled;
// <20> If the user chose a folder, see if it contains an existing
// Preferences file. If so, this folder becomes the new profile
// folder; otherwise, create a new folder inside it.
if ( userChoseFolder ) {
long parentID;
ThrowIfOSErr_( CFileMgr::GetFolderID(profileFolder, parentID) );
FSSpec prefFile;
prefFile.vRefNum = profileFolder.vRefNum;
prefFile.parID = parentID;
::GetIndString( prefFile.name, 300, prefFileName );
if (! CFileMgr::FileExists(prefFile)) {
// want to create a new folder inside the selected one
userChoseFolder = false;
profileFolder.parID = parentID;
}
}
// <20><>create a folder and return it
if ( !userChoseFolder )
{
LString::CopyPStr( profileName, profileFolder.name, 32 );
GetUniqueFolderName(profileFolder);
if ( oldNetscapeF )
{
// <20><>special case: point profile to existing 3.0 Netscape <20>
CFileMgr::MakeAliasFile( profileFolder, *oldNetscapeF );
profileFolder = *oldNetscapeF;
}
else
{
CreateDefaultProfileFolder(profileFolder);
}
}
return result;
}
ProfileErr CUserProfile::NewProfileWizard(
UpgradeEnum upgrading,
CStr31 &profileName,
const FSSpec &profileFolder,
FSSpec &newProfileFolder,
Boolean &userChoseFolder )
{
// <20> if we're upgrading 3.0 prefs, we don't allow the user to change
// the profile folder; just display & disable the default folder.
// Otherwise, the callback fills in the user name as the profile
// folder and lets the user edit it. (--this needs work)
LArray paneList( sizeof( PaneIDT ) );
#ifdef CAN_MAKE_DESKTOP_ICONS_FOR_PROFILE
PaneIDT normalPaneList[] = { profileIntroPane, userNamePane, profileNamePane,
profileFolderPane, profileIconsPane, profileDonePane, 0 };
PaneIDT mucPaneList[] = { profileIntroPane, profilePEPane, userNamePane, profileNamePane,
profileFolderPane, profileIconsPane, profileDonePane, 0 };
#else
PaneIDT normalPaneList[] = { profileIntroPane, userNamePane, profileNamePane,
profileFolderPane, profileDonePane, 0 };
PaneIDT mucPaneList[] = { profileIntroPane, profilePEPane, userNamePane, profileNamePane,
profileFolderPane, profileDonePane, 0 };
#endif
PaneIDT* tmpP;
if ( !mHasConfigPlugin )
tmpP = normalPaneList;
else
tmpP = mucPaneList;
while ( *tmpP != 0 )
paneList.InsertItemsAt( 1, LArray::index_Last, tmpP++ );
CDialogWizardHandler wizard( updateWizardDialog, paneList );
LListener* listener = new CProfilePaneMonitor( &wizard );
wizard.AddListener( listener );
LWindow* window = wizard.GetDialog();
if ( upgrading == eExistingPrefs )
{
wizard.SetEditText( 'name', CPrefs::GetString( CPrefs::UserName ) );
wizard.SetEditText( 'mail', CPrefs::GetString( CPrefs::UserEmail ) );
}
if ( upgrading != eNoUpgrade )
{
LStdControl* cancel = (LStdControl*)window->FindPaneByID( 'cncl' );
if (cancel)
{
CStr31 label;
GetIndString( label, kProfileStrings, kQuitLabel );
cancel->SetDescriptor( label );
}
}
// <20> hide "detected previous Navigator version" text if appropriate
if ( upgrading != eExistingPrefs || CPrefs::sPrefFileVersion != 3 )
{
LPane* upgradeText = window->FindPaneByID( 40 );
if ( upgradeText )
upgradeText->Hide();
upgradeText = window->FindPaneByID( 41 );
if ( upgradeText )
upgradeText->Hide();
}
FSSpec tempFolder;
tempFolder.vRefNum = profileFolder.vRefNum;
tempFolder.parID = profileFolder.parID;
LString::CopyPStr( "\p", tempFolder.name, 32 );
CFilePicker* picker = (CFilePicker*)window->FindPaneByID( 'fold' );
ThrowIfNil_( picker );
picker->SetPickType( CFilePicker::Folders );
picker->SetFSSpec( tempFolder, false );
// <20> don't allow different folder when upgrading
if ( upgrading == eExistingPrefs ) {
LPane* chooseBtn = picker->FindPaneByID(2);
LPane* chooseText = window->FindPaneByID(31);
if (chooseBtn && chooseText) {
chooseBtn->Hide();
chooseText->Hide();
}
}
// show the profile wizard
if ( wizard.DoWizard() == false )
{
// <20><>user cancelled
delete listener;
return eUserCancelled;
}
// copy user name & email to prefs; return profile name
CStr255 userName;
wizard.GetEditText( 'name', userName );
CPrefs::SetString( userName, CPrefs::UserName );
CStr255 emailAddr;
wizard.GetEditText( 'mail', emailAddr );
CPrefs::SetString( emailAddr, CPrefs::UserEmail );
wizard.GetEditText( 'pnam', profileName );
StripColons(profileName);
#ifdef CAN_MAKE_DESKTOP_ICONS_FOR_PROFILE
// make the desktop icons
OSErr err = MakeDesktopIcons(profileName, wizard.GetCheckboxValue('navb'), wizard.GetCheckboxValue('inbb'));
ThrowIfOSErr_(err); //should we do this?
#endif // CAN_MAKE_DESKTOP_ICONS_FOR_PROFILE
if ( picker->WasSet() )
{
userChoseFolder = true;
CFileMgr::CopyFSSpec( picker->GetFSSpec(), newProfileFolder );
}
delete listener;
if ( mHasConfigPlugin )
{
LControl* radioNew = (LControl*)window->FindPaneByID( 'Rnew' );
LControl* radioExs = (LControl*)window->FindPaneByID( 'Rexs' );
if ( ( radioNew && radioNew->GetValue() ) || upgrading != eNoUpgrade )
return eRunAccountSetup;
else if ( radioExs && radioExs->GetValue() /* ( upgrading != eNoUpgrade ) */)
return eRunMUC;
return eSkipMUC;
}
return eOK;
}
void CUserProfile::RenameProfile(short selectedID, CUserProfileDB& profileDB,
Cell& cell, ListHandle& listHand)
{
CStr31 newName;
if (profileDB.GetProfileName(selectedID, newName) == false)
return;
CStr255 prompt;
GetIndString(prompt, kProfileStrings, kRenamePrompt);
Boolean ok = UStdDialogs::AskStandardTextPrompt(nil, prompt, newName,
NULL, NULL, kStr31Len);
if (ok && newName.Length() > 0) {
LSetCell(&newName.fStr[1], newName.Length(), cell, listHand);
profileDB.SetProfileName(selectedID, newName);
}
}
void CUserProfile::DeleteProfile(short selectedID, CUserProfileDB& profileDB, ListHandle& listHand)
{
CStr255 prompt;
GetIndString(prompt, kProfileStrings, kDeletePrompt);
if (ErrorManager::PlainConfirm(prompt))
{
profileDB.DeleteProfile(selectedID);
if (--selectedID < 0)
selectedID = 0;
// redraw the profile list box
LDelRow(0, 0, listHand);
PopulateListBox(listHand, profileDB, selectedID);
}
}
// <20> Reflects profile name & path into xp preferences for querying by PE;
// also registers a callback so changing the name renames the profile.
// if we don't know how many profiles we have, pass -1 and the numprofiles
// pref will not be set (nasty hack: see CPrefs::InitPrefsFolder())
void
CUserProfile::ReflectToPreferences(const CStr31& profileName,
const FSSpec& profileFolder, short numProfiles)
{
char* folderPath = CFileMgr::EncodedPathNameFromFSSpec( profileFolder, true );
if ( folderPath )
{
PREF_SetDefaultCharPref( "profile.directory", folderPath );
free( folderPath );
}
PREF_SetDefaultCharPref( "profile.name", profileName );
if (numProfiles > -1)
PREF_SetDefaultIntPref( "profile.numprofiles", numProfiles );
PREF_RegisterCallback( "profile.name", ProfilePrefChangedFunc, NULL );
}
// <20> If a Defaults folder exists in Essential Files, copy it into
// Netscape Users and rename it to the selected profile name.
// Otherwise, or in case of a copying error, create a new folder.
void CUserProfile::CreateDefaultProfileFolder(const FSSpec& profileFolder)
{
OSErr err = noErr;
Boolean needToCreate = true;
FSSpec usersFolder;
CFileMgr::FolderSpecFromFolderID(profileFolder.vRefNum,
profileFolder.parID, usersFolder);
FSSpec templateFolder = CPrefs::GetFilePrototype(CPrefs::RequiredGutsFolder);
GetIndString( templateFolder.name, 300, profileTemplateDir );
if (CFileMgr::FileExists(templateFolder))
{
err = FSpDirectoryCopy( &templateFolder, &usersFolder,
nil, 0, true, nil );
if (err == noErr) {
needToCreate = false;
err = HRename(profileFolder.vRefNum, profileFolder.parID,
templateFolder.name, profileFolder.name);
}
}
if (needToCreate) {
short newRefNum;
long newParID;
err = CFileMgr::CreateFolderInFolder(
profileFolder.vRefNum, profileFolder.parID,
profileFolder.name, &newRefNum, &newParID );
}
ThrowIfOSErr_( err );
}
// <20><>find the network configuration plugin and return a function ptr.
// to it's only entry point if possible
void* CUserProfile::LoadConfigPlugin()
{
// BULLSHIT ALERT: Get out if I can't call GetSharedLibrary.
// Future: do the right thing for 68K. See bug#56245
long sSysArchitecture = 0;
if ( (Gestalt(gestaltSysArchitecture, &sSysArchitecture) != noErr)
|| (sSysArchitecture != gestaltPowerPC) )
{
// Can't determine what we _do_ have, or we determined that it's _not_ PPC...
return NULL;
}
Ptr main;
Str255 errName;
PE_PluginFuncType pluginFunc;
OSErr err = ::GetSharedLibrary( "\pMUP", kPowerPCCFragArch, kFindCFrag, &mConfigPluginID,
&main, errName );
if ( err != noErr )
{
err = ::GetSharedLibrary( "\pMUP", kPowerPCCFragArch, kLoadCFrag, &mConfigPluginID,
&main, errName );
}
if ( err == noErr )
{
CFragSymbolClass dontCare;
mPluginLoaded = TRUE;
err = ::FindSymbol( mConfigPluginID, "\pPE_PluginFunc", (Ptr*)&pluginFunc, &dontCare );
}
if ( err == noErr )
return pluginFunc;
return NULL;
}
// <20><>close the connection to the configuration plugin
OSErr CUserProfile::CloseConfigPlugin()
{
// if ( mPluginLoaded )
// return CloseConnection( &mConfigPluginID );
return noErr;
}
long CUserProfile::SendMessageToPlugin( long selector, void* pb )
{
OSErr err;
PE_PluginFuncType pluginFunc;
if ( !mHasConfigPlugin )
return -1;
pluginFunc = (PE_PluginFuncType)LoadConfigPlugin();
if ( pluginFunc )
{
union {
char buffer[ 1024 ];
MUCInfo mucInfo;
} tmp;
// <20><>call the stub to have it switch all the local machine
// stuff to use this user's configuration
err = (*pluginFunc)( selector, pb, tmp.buffer );
CloseConfigPlugin();
// if ( err == noErr && selector == kGetDialConfig )
// {
// cstring descString;
// PrettyPrintConfiguration( mucInfo, descString );
// inCaption->SetDescriptor( (CStr255)(char*)descString );
// }
return noErr;
}
return noErr;
}
/*****************************************************************************
*/
CUserProfileDB::CUserProfileDB( FSSpec& spec, Boolean createIt ): fFile( spec )
{
if ( createIt )
{
Try_
{
fFile.CreateNewFile( emSignature, 'PRFL' ); // ?? file type?
}
Catch_( inErr )
{
if ( inErr == dupFNErr )
;
else
Throw_( inErr );
}
}
fFile.OpenResourceFork( fsRdWrPerm );
}
short CUserProfileDB::CountProfiles()
{
return ::Count1Resources('STR ');
}
short CUserProfileDB::GetNextProfileID()
{
short nextUserID = CountProfiles();
return nextUserID;
}
short CUserProfileDB::GetProfileIDByUsername(const CString& username)
{
int id = kFirstProfileID, returnID = -1;
Handle hProfileData = GetDBResource('DATA', id);
ProfileDataHeader *pHeader;
char *profileUser;
while (hProfileData && (returnID == -1)) {
HLock(hProfileData);
pHeader = (ProfileDataHeader *) *hProfileData;
profileUser = ((char *) pHeader) + pHeader->firstOffset;
if (username == profileUser) {
returnID = id - kFirstProfileID;
}
HUnlock(hProfileData);
hProfileData = GetDBResource('DATA', ++id);
}
return returnID;
}
short CUserProfileDB::GetProfileIDByEmail(const CString& emailAddr)
{
int id = kFirstProfileID, returnID = -1;
Handle hProfileData = GetDBResource('DATA', id);
ProfileDataHeader *pHeader;
char *profileEmail;
while (hProfileData && (returnID == -1)) {
HLock(hProfileData);
pHeader = (ProfileDataHeader *) *hProfileData;
profileEmail = ((char *) pHeader) + pHeader->firstOffset
+ pHeader->nameLength;
if (emailAddr == profileEmail) {
returnID = id - kFirstProfileID;
}
HUnlock(hProfileData);
hProfileData = GetDBResource('DATA', ++id);
}
return returnID;
}
short CUserProfileDB::GetLastProfileID()
{
short lastUserID = kFirstProfileID;
short nextUserID = kFirstProfileID + GetNextProfileID();
// ID of the previous user is stored as a resource
Handle lastUser = GetDBResource('user', kFirstProfileID);
if (lastUser) {
lastUserID = **(short **) lastUser;
if (lastUserID >= nextUserID)
lastUserID = kFirstProfileID;
::ReleaseResource(lastUser);
}
return lastUserID - kFirstProfileID;
}
void CUserProfileDB::SetLastProfileID(short newUserID)
{
newUserID += kFirstProfileID;
Handle lastUser = GetDBResource('user', kFirstProfileID);
if (!lastUser) {
PtrToHand(&newUserID, &lastUser, sizeof(short));
::AddResource(lastUser, 'user', kFirstProfileID, nil);
}
else {
BlockMove(&newUserID, *lastUser, sizeof(short));
::ChangedResource(lastUser);
::ReleaseResource(lastUser);
}
}
void CUserProfileDB::AddNewProfile(short id, const CStr31& profileName, const FSSpec& profileFolder)
{
id += kFirstProfileID;
// create new STR, alis, and DATA resources
StringHandle nameHand;
PtrToHand(profileName, &(Handle) nameHand, profileName.Length() + 1);
AddResource((Handle) nameHand, 'STR ', id, nil);
AliasHandle alias;
OSErr err = NewAlias( nil, &profileFolder, &alias );
if (err == noErr) {
AddResource((Handle) alias, 'alis', id, profileFolder.name);
}
SetProfileData(id - kFirstProfileID);
}
Boolean CUserProfileDB::GetProfileName(short id, CStr31& name)
{
// -- use Get1Resource instead of GetString to avoid grabbing
// spurious strings from other programs (e.g. Kaleidoscope)
StringHandle strHand = (StringHandle) GetDBResource('STR ', id + kFirstProfileID);
if (strHand == nil)
return false;
HLock((Handle) strHand);
int len = *strHand[0] + 1;
if (len > 32) len = 32;
BlockMove(*strHand, name.fStr, len);
name.Length() = len - 1;
HUnlock((Handle) strHand);
ReleaseResource((Handle) strHand);
return true;
}
void CUserProfileDB::SetProfileName(short id, const CStr31& name)
{
StringHandle strHand = (StringHandle) GetDBResource('STR ', id + kFirstProfileID);
if (strHand) {
SetString(strHand, name);
ChangedResource((Handle) strHand);
ReleaseResource((Handle) strHand);
}
}
void CUserProfileDB::SetProfileData(short id)
{
Handle hProfileData;
ProfileDataHeader profileHeader;
short int dataLength;
long int dataOffset;
CStr255 userName;
CStr255 emailName;
XP_Bool addResource = false;
id += kFirstProfileID; // In order to allow this method to be called from
// outside the class, we have to allow the value in to
// be a "raw" profile number (i.e., as returned by
// GetLastProfile);
emailName = CPrefs::GetString(CPrefs::UserEmail);
userName = CPrefs::GetString(CPrefs::UserName);
profileHeader.count = 2;
profileHeader.firstOffset = sizeof(ProfileDataHeader);
/* (the +1 is for the null terminator for each string) */
profileHeader.nameLength = userName.Length() + 1;
profileHeader.emailLength = emailName.Length() + 1;
/* First, compute the length of the resource */
dataLength = sizeof(ProfileDataHeader) + profileHeader.nameLength + profileHeader.emailLength;
/* See if we're replacing or adding */
hProfileData = GetDBResource('DATA', id);
if (hProfileData) {
SetHandleSize(hProfileData, dataLength);
if (MemError() == noErr) {
XP_MEMSET(*hProfileData, '\0', dataLength);
} else {
ReleaseResource(hProfileData);
hProfileData = nil;
}
} else {
hProfileData = NewHandleClear(dataLength);
addResource = true;
}
if (hProfileData) {
dataOffset = 0;
HLock((Handle) hProfileData);
BlockMove(&profileHeader, *hProfileData, sizeof(ProfileDataHeader));
dataOffset = sizeof(ProfileDataHeader);
BlockMove(&(userName.fStr[1]), ((unsigned char *) *hProfileData) + dataOffset,
profileHeader.nameLength-1);
dataOffset += profileHeader.nameLength;
BlockMove(&(emailName.fStr[1]), ((unsigned char *) *hProfileData) + dataOffset,
profileHeader.emailLength-1);
HUnlock((Handle) hProfileData);
if (addResource) {
::AddResource(hProfileData, 'DATA', id, nil);
} else {
::ChangedResource(hProfileData);
::ReleaseResource(hProfileData);
}
}
}
Boolean CUserProfileDB::GetProfileAlias(short id, FSSpec& profileFolder, Boolean allowUserInteraction )
{
Boolean success = true;
AliasHandle a;
a = (AliasHandle) GetDBResource('alis', id + kFirstProfileID);
ThrowIfNil_(a);
Boolean changed;
OSErr err;
if ( allowUserInteraction )
{
err = ResolveAlias( NULL, a, &profileFolder, &changed );
// If the alias couldn't be resolved, give the user
// a chance to locate the profile folder
if (err < 0) {
success = false;
CStr255 errStr;
CStr31 profileName;
GetIndString(errStr, CUserProfile::kProfileStrings, CUserProfile::kBadAliasError);
GetProfileName(id, profileName);
StringParamText(errStr, profileName);
if (ErrorManager::PlainConfirm(errStr))
{
StandardFileReply reply;
reply.sfFile = CPrefs::GetFilePrototype(CPrefs::UsersFolder);
if ( CFilePicker::DoCustomGetFile(reply, CFilePicker::Folders, true) )
{
CFileMgr::CopyFSSpec(reply.sfFile, profileFolder);
Boolean changed;
err = UpdateAlias(nil, &reply.sfFile, a, &changed);
ThrowIfOSErr_(err);
ChangedResource((Handle) a);
success = true;
}
}
}
}
else
{
short aliasCount = 1;
err = MatchAlias( NULL, kARMMountVol | kARMNoUI | kARMMultVols | kARMSearch | kARMSearchMore,
a, &aliasCount, &profileFolder, &changed, NULL, NULL );
if ( err < 0 )
success = false;
}
ReleaseResource((Handle) a);
return success;
}
// This will change the value of selectedID if it becomes out of bounds
void CUserProfileDB::DeleteProfile(short selectedID)
{
selectedID += kFirstProfileID;
// delete profile resources and move the subsequent
// resources down to fill the space
Handle toDelete = GetDBResource('STR ', selectedID);
if (toDelete)
RemoveResource(toDelete);
toDelete = GetDBResource('alis', selectedID);
if (toDelete)
RemoveResource(toDelete);
toDelete = GetDBResource('DATA', selectedID);
if (toDelete)
RemoveResource(toDelete);
int id = selectedID + 1;
Handle next = GetDBResource('STR ', id);
while (next) {
::SetResInfo(next, id - 1, nil);
next = GetDBResource('DATA', id);
if (next) {
::SetResInfo(next, id - 1, nil);
ReleaseResource(next);
}
next = GetDBResource('alis', id);
if (next) {
::SetResInfo(next, id - 1, nil);
ReleaseResource(next);
}
// don't need to release strings because Populate uses them
next = GetDBResource('STR ', ++id);
}
}
Handle CUserProfileDB::GetDBResource(ResType theType, short theID)
{
StUseResFile resFile( fFile.GetResourceForkRefNum() );
return ::Get1Resource(theType, theID);
}
/*****************************************************************************
*/
const int cmd_NextPane = 8000;
const int cmd_PrevPane = 8001;
CProfilePaneMonitor::CProfilePaneMonitor( CDialogWizardHandler* wizard )
{
fWizard = wizard;
fCopiedName = false;
}
// !! This needs some work.
void CProfilePaneMonitor::ListenToMessage( MessageT inMessage, void* /* ioParam */)
{
PaneIDT nameField;
Boolean onNameField = false;
LView* window;
window = fWizard->GetDialog();
LStdControl* next = (LStdControl*)window->FindPaneByID( 'ok ' );
LStdControl* back = (LStdControl*)window->FindPaneByID( 'back' );
CStr255 buttonTitle;
if (fWizard->CurrentPane() == userNamePane) {
nameField = 'name';
onNameField = true;
}
else if (fWizard->CurrentPane() == profileNamePane) {
nameField = 'pnam';
onNameField = true;
}
if ( next && ( inMessage == cmd_NextPane || inMessage == cmd_PrevPane ) )
{
if ( fWizard->CurrentPaneNumber() == fWizard->TotalPanes() )
{
LControl* radioNew = (LControl*)window->FindPaneByID( 'Rnew' );
LControl* radioExs = (LControl*)window->FindPaneByID( 'Rexs' );
LPane* vnorm = (LView*)window->FindPaneByID('Vnor');
LPane* vexs = (LView*)window->FindPaneByID('Vexs');
LPane* vnew = (LView*)window->FindPaneByID('Vnew');
vnorm->Hide();
vexs->Hide();
vnew->Hide();
if ( radioExs && radioExs->GetValue() )
{
GetIndString( buttonTitle, CUserProfile::kProfileStrings, CUserProfile::kCreateProfileLabel );
vexs->Show();
}
else if ( radioNew && radioNew->GetValue() )
{
//GetIndString( buttonTitle, CUserProfile::kProfileStrings, CUserProfile::kDoneLabel );
GetIndString( buttonTitle, CUserProfile::kProfileStrings, CUserProfile::kRunASLabel );
vnew->Show();
}
else
{
GetIndString( buttonTitle, CUserProfile::kProfileStrings, CUserProfile::kDoneLabel );
vnorm->Show();
}
next->SetDescriptor( buttonTitle );
}
else
{
GetIndString( buttonTitle, CUserProfile::kProfileStrings, CUserProfile::kNextLabel );
next->SetDescriptor( buttonTitle );
}
}
if ( back && ( inMessage == cmd_NextPane || inMessage == cmd_PrevPane ) )
{
if ( fWizard->CurrentPaneNumber() == LArray::index_First )
back->Disable();
else
back->Enable();
}
// copy profile name to folder name, unless the user has changed
// the path or we're creating the default profile
if ( inMessage == cmd_NextPane && fWizard->CurrentPane() == profileFolderPane )
{
CStr31 profileName;
fWizard->GetEditText('pnam', profileName);
StripColons(profileName);
CFilePicker* picker = (CFilePicker*) fWizard->GetDialog()->FindPaneByID('fold');
if (picker && !picker->WasSet()) {
FSSpec folder = picker->GetFSSpec();
LString::CopyPStr(profileName, folder.name, 32);
CUserProfile::GetUniqueFolderName(folder);
picker->SetFSSpec(folder, false);
}
}
// copy user name to profile name (only do this once)
else if ( inMessage == cmd_NextPane && fWizard->CurrentPane() == profileNamePane
&& !fCopiedName)
{
CStr31 profileName;
fWizard->GetEditText('name', profileName);
StripColons(profileName);
if (profileName.Length() > kStr31Len)
profileName.Length() = kStr31Len;
fWizard->SetEditText('pnam', profileName);
fCopiedName = true;
}
// select Name field
if (onNameField && (inMessage == cmd_NextPane || inMessage == cmd_PrevPane)) {
LEditField* field = (LEditField*) fWizard->GetDialog()->FindPaneByID(nameField);
if (field) {
field->SwitchTarget(field);
field->SelectAll();
}
}
// disable Next button if user hasn't entered name
if (onNameField)
{
CStr255 text;
fWizard->GetEditText( nameField, text );
if ( text.Length() == 0 )
fWizard->DisableNextButton();
else
fWizard->EnableNextButton();
}
else
fWizard->EnableNextButton();
}
/*****************************************************************************
*/
CDialogWizardHandler::CDialogWizardHandler( ResIDT dlogID, LArray& paneList ):
fDialog( dlogID, CFrontApp::GetApplication() ), fPaneList( paneList )
{
ArrayIndexT index;
PaneIDT paneID;
LView* pane;
index = LArray::index_First;
fCurrentPane = LArray::index_First;
fListener = nil;
LWindow* window = fDialog.GetDialog();
ThrowIfNil_( window );
for ( index = LArray::index_First; index <= fPaneList.GetCount(); index++ )
{
fPaneList.FetchItemAt( index, &paneID );
LView::SetDefaultView( window );
if ( GetResource( 'PPob', paneID ) == nil )
break;
pane = (LView*)UReanimator::ReadObjects( 'PPob', paneID );
if ( pane )
{
if ( index != LArray::index_First )
pane->Hide();
pane->Enable();
pane->FinishCreate();
}
}
}
PaneIDT CDialogWizardHandler::CurrentPane()
{
PaneIDT paneID;
fPaneList.FetchItemAt( fCurrentPane, &paneID );
return paneID;
}
ArrayIndexT CDialogWizardHandler::CurrentPaneNumber()
{
return fCurrentPane;
}
ArrayIndexT CDialogWizardHandler::TotalPanes()
{
return fPaneList.GetCount();
}
void CDialogWizardHandler::AddListener(LListener* st)
{
fListener = st;
}
Boolean CDialogWizardHandler::DoWizard()
{
Boolean cancelled = false;
LWindow* window = fDialog.GetDialog();
ShowPane( fCurrentPane, window );
Boolean done = false;
while ( !done )
{
MessageT hit = fDialog.DoDialog();
switch ( hit )
{
case cmd_NextPane:
done = ShowPane( fCurrentPane + 1, window );
break;
case cmd_PrevPane:
done = ShowPane( fCurrentPane - 1, window );
break;
case msg_Cancel:
cancelled = done = true;
break;
}
if ( !done && fListener )
fListener->ListenToMessage( hit, nil );
}
return !cancelled;
}
Boolean CDialogWizardHandler::ShowPane( ArrayIndexT paneNum, LWindow* window )
{
PaneIDT paneID;
if ( paneNum < LArray::index_First )
return false;
if ( paneNum != fCurrentPane )
{
fPaneList.FetchItemAt( fCurrentPane, &paneID );
LPane* pane = window->FindPaneByID( paneID );
if ( pane )
pane->Hide();
}
fCurrentPane = paneNum;
if ( paneNum > fPaneList.GetCount() )
return true;
fPaneList.FetchItemAt( paneNum, &paneID );
LPane* pane = window->FindPaneByID( paneID );
if ( pane )
pane->Show();
return false;
}
void CDialogWizardHandler::EnableNextButton()
{
LWindow* window = fDialog.GetDialog();
if ( window )
{
LStdControl* next = (LStdControl*)window->FindPaneByID( 'ok ' );
if ( next )
next->Enable();
}
}
void CDialogWizardHandler::DisableNextButton()
{
LWindow* window = fDialog.GetDialog();
if ( window )
{
LStdControl* next = (LStdControl*)window->FindPaneByID( 'ok ' );
if ( next )
next->Disable();
}
}
LWindow* CDialogWizardHandler::GetDialog()
{
return fDialog.GetDialog();
}
void CDialogWizardHandler::SetEditText(PaneIDT paneID, const CString& text)
{
LWindow* window = fDialog.GetDialog();
if (window) {
LEditField* field = (LEditField*) window->FindPaneByID(paneID);
if (field) {
field->SetDescriptor(text);
}
}
}
void CDialogWizardHandler::GetEditText(PaneIDT paneID, CString& text)
{
LWindow* window = fDialog.GetDialog();
if (window) {
LEditField* field = (LEditField*) window->FindPaneByID(paneID);
if (field) {
field->GetDescriptor(text);
}
}
}
void CDialogWizardHandler::SetCheckboxValue(PaneIDT paneID, const Boolean value)
{
LWindow* window = fDialog.GetDialog();
if (window) {
LControl* checkbox = (LControl*) window->FindPaneByID(paneID);
if (checkbox) {
checkbox->SetValue((Int32)value);
}
}
}
Boolean CDialogWizardHandler::GetCheckboxValue(PaneIDT paneID)
{
LWindow* window = fDialog.GetDialog();
if (window) {
LControl* checkbox = (LControl*) window->FindPaneByID(paneID);
if (checkbox) {
return (Boolean)checkbox->GetValue();
}
}
return -1;
}