From 9f8a0a146643d65dbfd6fef35bb0e1acb5fe1f22 Mon Sep 17 00:00:00 2001 From: sfraser Date: Thu, 4 Jun 1998 06:57:39 +0000 Subject: [PATCH] First Checked In. git-svn-id: svn://10.0.0.236/trunk@3175 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/build/mac/CustomLib/CustomLib.c | 4 + mozilla/build/mac/CustomLib/CustomLib.mcp | Bin 0 -> 34536 bytes mozilla/cmd/macfe/central/userprofile.cp | 2018 +++++++++++++++++ mozilla/cmd/macfe/central/userprofile.h | 229 ++ mozilla/lib/plugin/MANIFEST | 6 + .../modules/edtplug/macbuild/edtplugLib.mcp | Bin 0 -> 55515 bytes 6 files changed, 2257 insertions(+) create mode 100644 mozilla/build/mac/CustomLib/CustomLib.c create mode 100644 mozilla/build/mac/CustomLib/CustomLib.mcp create mode 100644 mozilla/cmd/macfe/central/userprofile.cp create mode 100644 mozilla/cmd/macfe/central/userprofile.h create mode 100644 mozilla/lib/plugin/MANIFEST create mode 100644 mozilla/modules/edtplug/macbuild/edtplugLib.mcp diff --git a/mozilla/build/mac/CustomLib/CustomLib.c b/mozilla/build/mac/CustomLib/CustomLib.c new file mode 100644 index 00000000000..e9f979e05d4 --- /dev/null +++ b/mozilla/build/mac/CustomLib/CustomLib.c @@ -0,0 +1,4 @@ + +/* This library only exists to provide a dummy library for the final project */ + +/* There is nothing to do here. */ diff --git a/mozilla/build/mac/CustomLib/CustomLib.mcp b/mozilla/build/mac/CustomLib/CustomLib.mcp new file mode 100644 index 0000000000000000000000000000000000000000..c7a0e9a9aaa6af118a09b2cbecce27c051e3778f GIT binary patch literal 34536 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 F_#fdwpK$;H literal 0 HcmV?d00001 diff --git a/mozilla/cmd/macfe/central/userprofile.cp b/mozilla/cmd/macfe/central/userprofile.cp new file mode 100644 index 00000000000..5bc19224cc0 --- /dev/null +++ b/mozilla/cmd/macfe/central/userprofile.cp @@ -0,0 +1,2018 @@ +/* -*- 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 +#include +#include + + +#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; + + // ¥ÊprofileSpec here is "User Profiles" + profileSpec.vRefNum = usersFolder.vRefNum; + profileSpec.parID = usersFolder.parID; + GetIndString( profileSpec.name, 300, userProfiles ); + + // ¥Ê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(); + + // ¥Ê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 ) + { + // ¥ 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 ); + } + } + + // ¥ 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) { + // ¥Ê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(theDialog->FindPaneByID('addr')); + LEditField *searchBaseField = dynamic_cast(theDialog->FindPaneByID('sbas')); + LEditField *httpAddressField = dynamic_cast(theDialog->FindPaneByID('hurl')); + LControl * ldapRadio = dynamic_cast(theDialog->FindPaneByID('ldap')); + LControl * httpRadio = dynamic_cast(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(theDialog->FindPaneByID('user')); + LEditField *passwordField = dynamic_cast(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; +} + +// ¥Ê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 Ä 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 ); + + // ¥Ê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; + // ¥Êloop through wizard again if error + // don't loop 5/14/97 tgm + //done = false; + } + } + while ( 0 /*!done*/); + + ReflectToPreferences(profileName, profileFolder); + + return result; +} + +// ¥ 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(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 ) + // ¥Ê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; + + // ¥Ê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; + } + + // ¥ 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); + } + // ¥Ê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] = 'É'; + } + + 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] = 'É'; + } + + 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; +} + + +// ¥ 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; + + // ¥ 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; + } + } + + // ¥Êcreate a folder and return it + if ( !userChoseFolder ) + { + LString::CopyPStr( profileName, profileFolder.name, 32 ); + GetUniqueFolderName(profileFolder); + + if ( oldNetscapeF ) + { + // ¥Êspecial case: point profile to existing 3.0 Netscape Ä + 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 ) +{ + // ¥ 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 ); + } + } + + // ¥ 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 ); + // ¥ 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 ) + { + // ¥Ê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); + } +} + +// ¥ 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 ); +} + +// ¥ 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 ); +} + +// ¥Ê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; +} + +// ¥Ê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; + + // ¥Ê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; +} + diff --git a/mozilla/cmd/macfe/central/userprofile.h b/mozilla/cmd/macfe/central/userprofile.h new file mode 100644 index 00000000000..88bebbf8267 --- /dev/null +++ b/mozilla/cmd/macfe/central/userprofile.h @@ -0,0 +1,229 @@ +/* -*- 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. + */ + +#pragma once + +#include +#include "PascalString.h" +#include "StBlockingDialogHandler.h" + +const MessageT cmd_SelectProfile = 4000; +const MessageT cmd_NewProfile = 4001; +const MessageT cmd_DeleteProfile = 4002; +const MessageT cmd_RenameProfile = 4003; +const MessageT cmd_QuitProfile = 4004; +const MessageT cmd_EditDialSettings = 4010; +const MessageT cmd_LocationPopup = 4011; + +enum ProfileErr { + eUserCancelled = -2, + eUnknownError = -1, + eNeedUpgrade = 0, + eOK = 1, + eRunAccountSetup = 2, + eRunMUC = 3, + eSkipMUC = 4 +}; + + +/***************************************************************************** + * class CUserProfileDB + * + * Wrapper for multi-user profile database file. + * + *****************************************************************************/ +class CUserProfileDB +{ + +public: + + CUserProfileDB(FSSpec& spec, Boolean createIt = false); + + short CountProfiles(); + short GetNextProfileID(); + + short GetProfileIDByUsername(const CString& userName); + short GetProfileIDByEmail(const CString& emailAddr); + + short GetLastProfileID(); + void SetLastProfileID(short newUserID); + + void AddNewProfile(short id, const CStr31& profileName, + const FSSpec& profileFolder); + + Boolean GetProfileName(short id, CStr31& name); + void SetProfileName(short id, const CStr31& name); + + void SetProfileData(short id); + + Boolean GetProfileAlias(short id, FSSpec& profileFolder, Boolean allowUserInteraction = true); + void DeleteProfile(short selectedID); + + LFile * GetFile() {return &fFile;} + + +private: + LFile fFile; + Handle GetDBResource(ResType theType, short theID); + + enum { kFirstProfileID = 128 }; + +}; + + +/***************************************************************************** + * class CDialogWizardHandler + * + * A generic dialog wizard handler. + * + *****************************************************************************/ +class CDialogWizardHandler +{ +public: + CDialogWizardHandler( ResIDT dlogID, LArray& paneList ); + void AddListener(LListener* st); + + Boolean DoWizard(); + LWindow* GetDialog(); + + void GetEditText( PaneIDT paneID, CString& text ); + void SetEditText( PaneIDT paneID, const CString& text ); + + void SetCheckboxValue(PaneIDT paneID, const Boolean value); + Boolean GetCheckboxValue(PaneIDT paneID); + + PaneIDT CurrentPane(); + ArrayIndexT CurrentPaneNumber(); + ArrayIndexT TotalPanes(); + void EnableNextButton(); + void DisableNextButton(); + +protected: + Boolean ShowPane( ArrayIndexT paneNum, LWindow* window ); + + StBlockingDialogHandler fDialog; + LArray fPaneList; + ArrayIndexT fCurrentPane; + LListener* fListener; +}; + +/***************************************************************************** + * class CUserProfile + * + * Launches wizards and file operations for multi-user profile support. + * + *****************************************************************************/ +class CUserProfile +{ + +public: + static void InitUserProfiles(); + + // Opens the User Profiles registry and puts up a profile-selection + // dialog if there is more than one profile (or showDialog is true). + // Returns kNeedUpgrade if User Profiles does not exist (i.e. we need + // to call HandleUpgrade); else returns path of selected profile. + + static ProfileErr GetUserProfile( const FSSpec& usersFolder, + FSSpec& profileFolder, Boolean showDialog, short fileType ); + + // Creates a new network profile in the user's folder + static ProfileErr CreateNetProfile( FSSpec usersFolder, FSSpec& profileFolder ); + +private: + static ProfileErr DoNetProfileDialog(); + static void DoNetExtendedProfileDialog(LCommander * super); + +public: + // 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 Ä folder and the profile "folder" is an alias to it. + // Returns error code if user cancelled; else returns profile path. + + static ProfileErr HandleUpgrade( FSSpec& profileFolder, + const FSSpec* oldNetscapeF = nil ); + + // Creates a unique profile folder name if necessary + static void GetUniqueFolderName(FSSpec& folder); + + static short sCurrentProfileID; + + enum { kRenamePrompt = 1, + kDeletePrompt, + kReadError, + kCreateError, + kDefaultName, + kBadAliasError, + kQuitLabel, + kDoneLabel, + kNextLabel, + kConfigFileError, + kInvalidConfigFile, + kRunASLabel, + kCreateProfileLabel, + kConfigurationFileName }; + enum { kProfileStrings = 900 }; + +private: + static ProfileErr HandleProfileDialog( FSSpec& profileSpec, CUserProfileDB& profileDB, + FSSpec& profileFolder, short& newUserID, short lastUserID, + Boolean wantsProfileManager ); + static void PopulateListBox( ListHandle& listHand, CUserProfileDB& profileDB, + short defaultID ); + + enum UpgradeEnum { eNoUpgrade, // an additional profile is being created + eExistingPrefs, // first profile, existing Netscape Prefs file + eNewInstall }; // first profile, fresh install + + static ProfileErr NewUserProfile( const FSSpec& profileSpec, FSSpec& profileFolder, + CStr31& profileName, UpgradeEnum upgrading = eNoUpgrade, + const FSSpec* oldNetscapeF = nil ); + static ProfileErr NewProfileWizard( UpgradeEnum upgrading, CStr31& profileName, + const FSSpec& profileFolder, FSSpec& newProfileFolder, + Boolean& userChoseFolder ); + + static void RenameProfile( short selectedID, CUserProfileDB& profileDB, + Cell& cell, ListHandle& listHand ); + static void DeleteProfile( short selectedID, CUserProfileDB& profileDB, + ListHandle& listHand ); + + static void ReflectToPreferences(const CStr31& profileName, + const FSSpec& profileFolder, short numProfiles = 1); + static void CreateDefaultProfileFolder(const FSSpec& profileFolder); + + static OSErr MakeDesktopIcons(const CStr31& profileName, + const Boolean wantsNavigator, const Boolean wantsInbox); + + enum { kInvalidProfileID = -1 }; + +protected: + // ¥ÊinPrefsFolder is the FSSpec of the users Preferences + // folderÉ we read a file directly below that + static long SendMessageToPlugin( long inMessage, void* pb = NULL ); + + static void* LoadConfigPlugin(); // really returns PE_PluginFuncType + static OSErr CloseConfigPlugin(); + + static Boolean DeleteMagicProfile( FSSpec& inSpec ); + + static CFragConnectionID mConfigPluginID; + static Boolean mHasConfigPlugin; + static Boolean mPluginLoaded; +}; + diff --git a/mozilla/lib/plugin/MANIFEST b/mozilla/lib/plugin/MANIFEST new file mode 100644 index 00000000000..ae7d2cc0a8c --- /dev/null +++ b/mozilla/lib/plugin/MANIFEST @@ -0,0 +1,6 @@ +nppg.h +npupp.h +nsIPlug.h +nsILCPlg.h +npglue.h +nppriv.h diff --git a/mozilla/modules/edtplug/macbuild/edtplugLib.mcp b/mozilla/modules/edtplug/macbuild/edtplugLib.mcp new file mode 100644 index 0000000000000000000000000000000000000000..63a65fd3ff3e83c4de9697ba8d2fbd06e946361b GIT binary patch literal 55515 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 literal 0 HcmV?d00001