home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / macfe / central / profile.cp < prev    next >
Encoding:
Text File  |  1998-04-08  |  54.7 KB  |  2,020 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include "profile.h"
  20. #include "client.h"
  21. #include "UStdDialogs.h"
  22. #include "ufilemgr.h"
  23. #include "uerrmgr.h"
  24. #include "uapp.h"
  25. #include "uprefd.h"
  26. #include "prefwutil.h"
  27. #include "macutil.h"
  28. #include "prefapi.h"
  29. #include "resgui.h"
  30. #include "xp_file_mac.h"
  31. #include "DirectoryCopy.h"
  32. #include <LGARadioButton.h>
  33. #include <LGAPushButton.h>
  34. #include <LGAEditField.h>
  35.  
  36. // for multi-user profile support in PE
  37. #include "MUC.h"
  38. #include <CodeFragments.h>
  39. #include <LString.h>
  40.  
  41. #define updateWizardDialog        9800
  42.  
  43. #define profilePEPane            9801
  44. #define profileIntroPane        9802
  45. #define userNamePane            9803
  46. #define profileNamePane            9804
  47. #define profileFolderPane        9805
  48. #define profileIconsPane        9806
  49. #define profileDonePane            9807
  50.  
  51. #define profileSelectDialog        9900
  52. #define profileManagerDialog    9901
  53.  
  54. // NOTE: Magic name must be kept in sync with ns/modules/libreg/src/reg.h
  55. #define MAGIC_PROFILE_NAME        "User1"
  56.  
  57. const char* kProfileNamePref = "profile.name";
  58.  
  59. /*****************************************************************************
  60.  * The resource format for storing profile metadata (i.e., username and 
  61.  * email) in the profile database so it can be easily searched.  In order
  62.  * to allow an arbitrary amount of metadata, the resource is divided into
  63.  * a header section, which counts the number of metadata items and the length
  64.  * to each, and a data section, which simply consists of the data in packed
  65.  * format.  The offset to each set of data is the sum of the first offset
  66.  * plus all of the lengths.  Strings are null terminated for convenience.
  67.  * All of this is stored in the profile database in a 'DATA' resource
  68.  * which corresponds to the id of the profile in use.
  69.  ****************************************************************************/
  70.  
  71. /* The version of the metadata for Nav 4.0 */
  72.  
  73. typedef struct {
  74.     short int        count;
  75.     short int        firstOffset;
  76.     long int        nameLength;
  77.     long int        emailLength;
  78.     /* New data element lengths would go here, along with a corresponding
  79.        change in the count and firstOffset items */
  80.     /* Data follows here */
  81. } ProfileDataHeader;
  82.  
  83. MODULE_PRIVATE int PR_CALLBACK ProfilePrefChangedFunc(const char *pref, void *data);
  84.  
  85. CFragConnectionID CUserProfile::mConfigPluginID;
  86.  
  87. class LWhiteListBox: public LListBox
  88. {
  89. #if !defined(__MWERKS__) || (__MWERKS__ >= 0x2000)
  90.     typedef LListBox inherited;
  91. #endif
  92.  
  93. public:
  94.     enum    { class_ID = 'Lwht' };
  95.     
  96.                         LWhiteListBox( LStream* inStream );
  97.     
  98.     virtual Boolean        FocusDraw(LPane* inSubPane = nil);
  99.     virtual void        DrawSelf();
  100. };
  101.  
  102. LWhiteListBox::LWhiteListBox( LStream* inStream ): LListBox( inStream )
  103. {
  104. }
  105.  
  106. Boolean LWhiteListBox::FocusDraw(LPane* /*inSubPane*/)
  107. {
  108.     const RGBColor rgbWhite = { 0xFFFF, 0xFFFF, 0xFFFF };
  109.     
  110.     if ( inherited::FocusDraw() )
  111.     {
  112.         ::RGBBackColor( &rgbWhite );
  113.         return TRUE;
  114.     }
  115.     return FALSE;
  116. }
  117.  
  118. void LWhiteListBox::DrawSelf()
  119. {
  120.     Rect    frame;
  121.     
  122.     this->CalcLocalFrameRect( frame );
  123.     ::EraseRect( &frame );
  124.     LListBox::DrawSelf();    
  125. }
  126.  
  127. MODULE_PRIVATE int PR_CALLBACK ProfilePrefChangedFunc(const char *pref, void * /* data */) 
  128. {
  129.     FSSpec profileSpec = CPrefs::GetFilePrototype(CPrefs::UsersFolder);        
  130.     GetIndString(profileSpec.name, 300, userProfiles);
  131.  
  132.     CUserProfileDB        profile(profileSpec);
  133.  
  134.     if ((!XP_STRCASECMP(pref,"mail.identity.username")) ||
  135.         (!XP_STRCASECMP(pref,"mail.identity.useremail")))
  136.     {
  137.         profile.SetProfileData( CUserProfile::sCurrentProfileID );            
  138.     }
  139.     else if (!XP_STRCMP(pref, kProfileNamePref))
  140.     {
  141.         char profileName[255];
  142.         int len = 255;
  143.         if ( PREF_GetCharPref(kProfileNamePref, profileName, &len) == PREF_NOERROR )
  144.         {        
  145.             profile.SetProfileName( CUserProfile::sCurrentProfileID, (CStr255) profileName );
  146.         }
  147.     }
  148.     
  149.     return 0;
  150. }
  151.  
  152. class CProfilePaneMonitor : public LListener
  153. {
  154.     public:
  155.         CProfilePaneMonitor(CDialogWizardHandler*);
  156.         virtual void    ListenToMessage(MessageT inMessage, void *ioParam);
  157.     
  158.     private:
  159.         CDialogWizardHandler*    fWizard;
  160.         Boolean    fCopiedName;
  161. };
  162.  
  163. /*****************************************************************************
  164.  * class CUserProfile
  165.  *
  166.  * Dialog handlers & wizards for multi-user profile support.
  167.  *
  168.  *****************************************************************************/
  169.  
  170. short CUserProfile::sCurrentProfileID = CUserProfile::kInvalidProfileID;
  171. Boolean CUserProfile::mHasConfigPlugin = FALSE;
  172. Boolean CUserProfile::mPluginLoaded = FALSE;
  173.  
  174. void CUserProfile::InitUserProfiles()
  175. {
  176.     mHasConfigPlugin = ( LoadConfigPlugin() != NULL );
  177.     if ( mHasConfigPlugin )
  178.         CloseConfigPlugin();        
  179. }
  180.  
  181. // Attempts to open "User Profiles" and put up a selection dialog.
  182. // Returns the location of the user's selected Prefs folder.
  183. ProfileErr
  184. CUserProfile::GetUserProfile( const FSSpec& usersFolder, FSSpec& profileFolder,
  185.     Boolean showDialog, short fileType )
  186. {
  187.     ProfileErr        result = eOK;
  188.     Boolean            done = true;
  189.     Boolean            wantsProfileManager = showDialog;
  190.     FSSpec            profileSpec;
  191.     short            numProfiles = 1;
  192.     CStr31            profileName;
  193.     
  194.     // Ñ╩profileSpec here is "User Profiles"
  195.     profileSpec.vRefNum = usersFolder.vRefNum;
  196.     profileSpec.parID = usersFolder.parID;
  197.     GetIndString( profileSpec.name, 300, userProfiles );
  198.     
  199.     // Ñ╩I have no idea why this is so convoluted
  200.     
  201.     if ( !CFileMgr::FileExists( profileSpec ) )
  202.         return eNeedUpgrade;
  203.     
  204.     if ( DeleteMagicProfile( profileSpec ) )
  205.         return eNeedUpgrade;
  206.  
  207.     CUserProfileDB        profileDB( profileSpec );
  208.     do
  209.     {
  210.         Try_
  211.         {
  212.             short        newUserID = 0;
  213.             short        lastUserID = profileDB.GetLastProfileID();
  214.             
  215.             // Ñ╩only put up dialog if there's more than one user
  216.             if ( showDialog || profileDB.CountProfiles() > 1 )
  217.             {
  218.                 // HACK ALERT!!!!!
  219.                 // If we're being asked to open a doc or get a URL just skip the dialog
  220.                 // and use the last profile that was selected
  221.                 if ( (fileType == FILE_TYPE_ODOC) || (fileType == FILE_TYPE_GETURL) )
  222.                 {
  223.                     newUserID = lastUserID;
  224.                     if ( profileDB.GetProfileAlias( newUserID, profileFolder ) )
  225.                         result = eOK;
  226.                     else    
  227.                         result = eUnknownError;
  228.  
  229.                 }
  230.                 else
  231.                 // END HACK ALERT!!!!!
  232.                     result = HandleProfileDialog(
  233.                         profileSpec,
  234.                         profileDB,
  235.                         profileFolder,
  236.                         newUserID,
  237.                         lastUserID,
  238.                         wantsProfileManager );
  239.                     
  240.                 if ( result >= 0 && lastUserID != newUserID )
  241.                     profileDB.SetLastProfileID( newUserID );
  242.                 
  243.                 if ( result >= eOK )
  244.                     PREF_RegisterCallback("mail.identity",ProfilePrefChangedFunc, NULL);
  245.                 done = true;
  246.             }
  247.             else
  248.             {
  249.                 newUserID = lastUserID;
  250.                 Try_
  251.                 {
  252.                     if ( profileDB.GetProfileAlias( lastUserID, profileFolder ) )
  253.                         result = eOK;
  254.                     else    
  255.                         result = eUnknownError;
  256.                 }
  257.                 Catch_ ( inErr )
  258.                 {
  259.                     CStr255 errStr;
  260.                     GetIndString( errStr, kProfileStrings, kReadError );
  261.                     ErrorManager::ErrorNotify( inErr, errStr );
  262.                 }
  263.                 
  264.                 if ( result < eOK )
  265.                 {
  266.                     // Ñ if we failed to load the profile, loop back to the
  267.                     // beginning and force Profile Manager to appear
  268.                     done = false;
  269.                     showDialog = wantsProfileManager = true;
  270.                 }
  271.                 else
  272.                 {
  273.                     long        err;
  274.                     err = SendMessageToPlugin( kAutoSelectDialConfig, &profileFolder );
  275.                     if ( err == errProfileNotFound )
  276.                         SendMessageToPlugin( kEditDialConfig, &profileFolder );
  277.                                                 
  278.                     PREF_RegisterCallback( "mail.identity",ProfilePrefChangedFunc, NULL );
  279.                 }
  280.             }
  281.             
  282.             // Ñ save the previous user ID back to profile db
  283.             if ( result >= eOK )
  284.             {
  285.                 sCurrentProfileID = newUserID;
  286.                 numProfiles = profileDB.CountProfiles();
  287.             }
  288.         }
  289.         Catch_ ( inErr )
  290.         {
  291.             CStr255        errStr;
  292.             GetIndString( errStr, kProfileStrings, kReadError );
  293.             ErrorManager::ErrorNotify( inErr, errStr );
  294.             result = eUnknownError;
  295.         }
  296.     }
  297.     while ( !done );
  298.     
  299.     if (result != eUserCancelled) {
  300.         // Ñ╩reflect path & name into xp preferences
  301.         if (sCurrentProfileID != kInvalidProfileID)
  302.             profileDB.GetProfileName( sCurrentProfileID, profileName );
  303.         ReflectToPreferences(profileName, profileFolder, numProfiles);    
  304.     }
  305.     return result;
  306. }
  307.  
  308. static void PrefToEditField(const char * prefName, LGAEditField * field);
  309. static void EditFieldToPref(LGAEditField * field, const char * prefName);
  310.  
  311. #define PREF_STRING_LEN 255
  312. void PrefToEditField(const char * prefName, LGAEditField * field)
  313. {
  314.     int prefStringLen;
  315.     char prefString[PREF_STRING_LEN];
  316.     prefStringLen = PREF_STRING_LEN;
  317.     if ( PREF_GetCharPref(prefName, prefString, &prefStringLen) == 0 )
  318.     {
  319.         c2pstr(prefString);
  320.         field->SetDescriptor((unsigned char *)prefString);
  321.     }
  322. }
  323.  
  324. void EditFieldToPref(LGAEditField * field, const char * prefName)
  325. {
  326.     Str255 s;
  327.     field->GetDescriptor(s);
  328.     p2cstr(s);
  329.     PREF_SetCharPref(prefName, (char*)s);
  330. }
  331.  
  332. // Displays the additional data login dialog. Throws are taken care of by
  333. // the caller
  334. void
  335. CUserProfile::DoNetExtendedProfileDialog(LCommander * super)
  336. {
  337.     StDialogHandler    theHandler(9911, super);
  338.     LWindow            *theDialog = theHandler.GetDialog();
  339.     
  340.     LGAEditField *ldapAddressField = (LGAEditField*)theDialog->FindPaneByID('addr');
  341.     LGAEditField *searchBaseField = (LGAEditField*)theDialog->FindPaneByID('sbas');
  342.     LGAEditField *httpAddressField = (LGAEditField*)theDialog->FindPaneByID('hurl');
  343.     LGARadioButton * ldapRadio = (LGARadioButton *)theDialog->FindPaneByID('ldap');
  344.     LGARadioButton * httpRadio = (LGARadioButton *)theDialog->FindPaneByID('http');
  345.     
  346.     ThrowIfNil_(ldapAddressField);
  347.     ThrowIfNil_(searchBaseField);
  348.     ThrowIfNil_(httpAddressField);
  349.     ThrowIfNil_(ldapRadio);
  350.     ThrowIfNil_(httpRadio);
  351.  
  352. // Initialize the dialog from the preferences
  353. //    PrefToEditField("li.server.ldap.serverName", ldapAddressField );
  354. //    PrefToEditField("li.server.ldap.searchBase", searchBaseField );
  355. //    PrefToEditField("li.server.http.baseURL", httpAddressField);
  356.     ldapRadio->SetValue(1);
  357.     int prefStringLen;
  358.     char prefString[PREF_STRING_LEN];
  359.     prefStringLen = PREF_STRING_LEN;
  360.     if ( PREF_GetCharPref("li.protocol", prefString, &prefStringLen) == 0 )
  361.         if (XP_STRCMP(prefString, "http") == 0)
  362.             httpRadio->SetValue(1);
  363.  
  364. // Do the dialog
  365.     httpAddressField->SelectAll();
  366.     theDialog->SetLatentSub(httpAddressField);
  367.     theDialog->Show();
  368.     
  369.     while (true) 
  370.     {
  371.         MessageT    hitMessage = theHandler.DoDialog();
  372.         if ( hitMessage == msg_Cancel )
  373.             break;
  374.         else if ( hitMessage == msg_OK )
  375.         {
  376.             
  377.             LStr255 httpAddress;
  378.             httpAddressField->GetDescriptor(httpAddress);
  379.             if ( httpAddress.Length() > 2 )
  380.             {
  381.                 if (!httpAddress.BeginsWith(LStr255("http://")))
  382.                     httpAddress.Insert(LStr255("http://"), 0);
  383.             }
  384.             EditFieldToPref(ldapAddressField, "li.server.ldap.serverName");
  385.             EditFieldToPref(searchBaseField, "li.server.ldap.searchBase");
  386.             EditFieldToPref(httpAddressField, "li.server.http.baseURL");
  387.         
  388.             if ( ldapRadio->GetValue() > 0 )
  389.                 PREF_SetCharPref("li.protocol", "ldap");
  390.             else
  391.                 PREF_SetCharPref("li.protocol", "http");
  392.  
  393.             break;
  394.         }
  395.     }
  396. }
  397.  
  398. // Displays the modal login dialog
  399. ProfileErr
  400. CUserProfile::DoNetProfileDialog()
  401. {
  402.     ProfileErr perr = eOK;
  403.     try
  404.     {
  405.         StDialogHandler    theHandler(9910, CFrontApp::GetApplication());
  406.         LWindow            *theDialog = theHandler.GetDialog();
  407.  
  408.         LGAEditField *usernameField = (LGAEditField*)theDialog->FindPaneByID('user');
  409.         LGAEditField *passwordField = (LGAEditField*)theDialog->FindPaneByID('pass');
  410.  
  411.         ThrowIfNil_(usernameField);
  412.         ThrowIfNil_(passwordField);
  413.         
  414.         usernameField->SelectAll();
  415.         theDialog->SetLatentSub(usernameField);
  416.         theDialog->Show();
  417.  
  418.         while (true) 
  419.         {
  420.             MessageT    hitMessage = theHandler.DoDialog();
  421.             
  422.             if (hitMessage == msg_Cancel) 
  423.             {
  424.                 perr = eUserCancelled;
  425.                 break;
  426.             } 
  427.             else if (hitMessage == msg_OK) 
  428.             {
  429.                 EditFieldToPref( usernameField, "li.login.name");
  430.                 EditFieldToPref( passwordField, "li.login.password");
  431.  
  432.                 PREF_SetBoolPref("li.enabled", true);
  433.                 perr = eOK;
  434.                 break;
  435.             }
  436.             else if (hitMessage == 'adva')    // Advanced button
  437.             {
  438.                 DoNetExtendedProfileDialog(theDialog);
  439.             }
  440.         }
  441.     }
  442.     catch (ExceptionCode err)
  443.     {
  444.         XP_ASSERT(false);
  445.         perr = eUnknownError;
  446.     }
  447.     
  448.     return perr;
  449. }
  450.  
  451. // Creates a network profile folder
  452. // The folder is located inside the users folder
  453. ProfileErr 
  454. CUserProfile::CreateNetProfile( FSSpec usersFolder, FSSpec& profileFolderSpec )
  455. {    
  456.     ProfileErr perr;
  457.     perr = DoNetProfileDialog();
  458.     
  459.     if (perr == eOK)
  460.     {
  461.     try
  462.     {
  463.             CStr255 profileFolderName("Temporary Profile");
  464.             OSErr err;
  465.             
  466.         // Create the folder spec of the profile directory
  467.             profileFolderSpec = usersFolder;
  468.             LString::CopyPStr(profileFolderName, profileFolderSpec.name, sizeof(profileFolderSpec.name));
  469.             
  470.         // If the folder already exists, delete it
  471.             err = CFileMgr::DeleteFolder( profileFolderSpec );
  472.             XP_ASSERT((err == noErr) || (err == fnfErr));
  473.  
  474.         // Create the folder
  475.             short dummy; 
  476.             long dummy2;
  477.             err = CFileMgr::CreateFolderInFolder(usersFolder.vRefNum, usersFolder.parID, profileFolderName, 
  478.                             &dummy, &dummy2);
  479.             ThrowIfOSErr_(err);
  480.             ReflectToPreferences( CStr255("Network Profile"), profileFolderSpec);
  481.         }
  482.         catch (ExceptionCode err)
  483.         {
  484.             XP_ASSERT(false);
  485.             return eUnknownError;
  486.         }
  487.     }
  488.  
  489.     return perr;
  490. }
  491.  
  492. // Ñ╩launches upgrade wizard for users who have not run 4.0 before
  493. // creates an initial profile folder and User Profiles file.
  494. // if oldNetscapeF is non-null, it points to the user's 3.0
  495. // Netscape ─ folder and the profile "folder" is an alias to it
  496. ProfileErr
  497. CUserProfile::HandleUpgrade( FSSpec& profileFolder, const FSSpec* oldNetscapeF )
  498. {
  499.     ProfileErr        result = eOK;
  500.     CStr31            profileName;
  501.     
  502.     do 
  503.     {
  504.         Try_
  505.         {
  506.             FSSpec profileSpec = CPrefs::GetFilePrototype( CPrefs::UsersFolder );
  507.             
  508.             if ( mHasConfigPlugin && !oldNetscapeF )
  509.             {
  510.                 profileFolder.vRefNum = profileSpec.vRefNum;
  511.                 profileFolder.parID = profileSpec.parID;
  512.                 profileName = MAGIC_PROFILE_NAME;
  513.                 LString::CopyPStr( profileName, profileFolder.name, 32 );
  514.  
  515.                 CreateDefaultProfileFolder( profileFolder );
  516.                 result = eRunAccountSetup;
  517.             }
  518.             else
  519.             {
  520.                 UpgradeEnum upgrading = (oldNetscapeF == nil) ? eNewInstall : eExistingPrefs;
  521.                 result = NewUserProfile( profileSpec, profileFolder, profileName,
  522.                      upgrading, oldNetscapeF );
  523.             }
  524.             if ( result == eUserCancelled )
  525.                 return eUserCancelled;
  526.             
  527.             if ( profileName.Length() == 0 )
  528.                 GetIndString( profileName, kProfileStrings, kDefaultName );
  529.  
  530.             // Ñ╩create Profiles file and add the alias
  531.             GetIndString( profileSpec.name, 300, userProfiles );
  532.             CUserProfileDB profileDB( profileSpec, true );
  533.             
  534.             profileDB.AddNewProfile( 0, profileName, profileFolder );
  535.             sCurrentProfileID = 0;
  536.         }
  537.         Catch_( inErr )
  538.         {
  539.             CStr255        errStr;
  540.             GetIndString( errStr, kProfileStrings, kCreateError );
  541.             ErrorManager::ErrorNotify( inErr, errStr );
  542.             result = eUnknownError;
  543.             // Ñ╩loop through wizard again if error 
  544.             // don't loop 5/14/97 tgm
  545.             //done = false;
  546.         }
  547.     }
  548.     while ( 0 /*!done*/);
  549.     
  550.     ReflectToPreferences(profileName, profileFolder);
  551.     
  552.     return result;
  553. }
  554.  
  555. // Ñ puts up user-selection dialog and returns selected user ID
  556. ProfileErr CUserProfile::HandleProfileDialog(
  557.     FSSpec& profileSpec,
  558.     CUserProfileDB& profileDB,
  559.     FSSpec& profileFolder,
  560.     short& newUserID,
  561.     short lastUserID,
  562.     Boolean    wantsProfileManager )
  563. {
  564.     int                    dialogID = wantsProfileManager ?
  565.         profileManagerDialog : profileSelectDialog;
  566.     Boolean                success = false;
  567.     LListBox*            listBox;
  568.     LGAPushButton*        okButton;
  569.     LPane*                newButton;
  570.     LPane*                deleteButton;
  571.     LPane*                renameButton;
  572.     LPane*                optionsButton;
  573.     
  574.     ProfileErr            result = eOK;
  575.         
  576.     RegisterClass_( LWhiteListBox);
  577.         
  578.     StBlockingDialogHandler dialog( dialogID, CFrontApp::GetApplication() );
  579.     
  580.     listBox = (LListBox*)dialog.GetDialog()->FindPaneByID( 'user' );
  581.     ThrowIfNil_( listBox );
  582.     ListHandle listHand = listBox->GetMacListH();
  583.     (**listHand).selFlags = lOnlyOne + lNoNilHilite;        // only one selection
  584.  
  585.     LAddColumn( 1, 0, listHand );
  586.     PopulateListBox( listHand, profileDB, lastUserID );
  587.  
  588.     listBox->AddListener( &dialog );
  589.     listBox->SwitchTarget( listBox );
  590.     
  591.     okButton = (LGAPushButton*)dialog.GetDialog()->FindPaneByID( 'ok  ' );
  592.     deleteButton = dialog.GetDialog()->FindPaneByID( 2 );
  593.     renameButton = dialog.GetDialog()->FindPaneByID( 3 );
  594.     newButton = dialog.GetDialog()->FindPaneByID( 1 );
  595.     optionsButton = dialog.GetDialog()->FindPaneByID( 'Ebut' );
  596.     
  597.     if ( wantsProfileManager )
  598.         ThrowIfNil_( okButton && deleteButton && renameButton && newButton );
  599.     else
  600.         ThrowIfNil_( okButton );
  601.  
  602.     if ( !mHasConfigPlugin )
  603.     {
  604.         if ( optionsButton )
  605.             optionsButton->Hide();
  606.     }
  607.     else
  608.     {
  609.         if ( !wantsProfileManager )
  610.             SendMessageToPlugin( kInitListener, (LDialogBox*)dialog.GetDialog() );
  611.     }
  612.      
  613.     short tempUserID = -1;
  614.     
  615.     /* keep track of the amount of time we've been idly showing this dialog */
  616.     long     startTime         =     TickCount();
  617.     long     elapsedTime        =    0;
  618.     long     secsLeft        =    20;  //we can also get this from a resource in the User Profiles file if it exists.        
  619.     Boolean    keepCounting        =    true; // (!wantsProfileManager); /* only countdown in simple profile picker. not manager*/
  620.     const    ResIDT    autoStartResID = 9999;        
  621.                 
  622.     // Check to see if our secret keep counting resource exists - if not, use default secsLeft
  623.     StUseResFile resFile( profileDB.GetFile()->GetResourceForkRefNum() );
  624.     StringHandle numSecsStringH = (StringHandle) ::Get1Resource('TEXT', autoStartResID);
  625.     if (keepCounting && numSecsStringH)
  626.     {
  627.         char buffer[4];
  628.         buffer[sizeof(buffer)-1] = 0;
  629.         
  630.         memcpy( (unsigned char *)buffer, (unsigned char *)*numSecsStringH, min(GetHandleSize((Handle)numSecsStringH),(long)sizeof(buffer)-1));
  631.         secsLeft = atoi(buffer);
  632.         if (secsLeft <= 0)
  633.             keepCounting = false;            
  634.     }
  635.     
  636.     
  637.     while ( !success ) 
  638.     {
  639.         //╩Ñ catch any errors inside dialog loop
  640.         Try_
  641.         {
  642.             Cell    cell;
  643.             
  644.             MessageT hit = dialog.DoDialog();
  645.             
  646.             // default to selecting the last selected profile if enough time has elapsed
  647.             if (keepCounting && (secsLeft <= 0))
  648.             {
  649.                 okButton->SimulateHotSpotClick(1);
  650.                 hit = cmd_SelectProfile;
  651.             }
  652.             else if (keepCounting)
  653.             {
  654.                 // update secsLeft
  655.                 elapsedTime = TickCount() - startTime;
  656.                 if (elapsedTime >= 60)
  657.                 {
  658.                     secsLeft--;
  659.                     startTime = TickCount();
  660.                 }
  661.             }
  662.             else if (secsLeft >= 0)
  663.                 secsLeft = -1;
  664.             
  665.             if (listBox->GetLastSelectedCell( cell ) )
  666.             {
  667.                 newUserID = cell.v;
  668.                 okButton->Enable();
  669.                 if (wantsProfileManager) {
  670.                     renameButton->Enable();
  671.                     if ( profileDB.CountProfiles() > 1 )
  672.                         // Ñ╩don't allow deleting last profile
  673.                         deleteButton->Enable();
  674.                     else
  675.                         deleteButton->Disable();
  676.                 }
  677.                 if ( optionsButton )
  678.                     optionsButton->Enable();
  679.             }
  680.             else
  681.             {
  682.                 newUserID = -1;
  683.                 okButton->Disable();
  684.                 if (wantsProfileManager) {
  685.                     renameButton->Disable();
  686.                     deleteButton->Disable();
  687.                 }
  688.                 if ( optionsButton )
  689.                     optionsButton->Disable();
  690.             }
  691.             
  692.             if ( newUserID != tempUserID )
  693.             {
  694.                 if (tempUserID > -1)
  695.                     keepCounting = false;
  696.                 if ( newUserID != -1 && mHasConfigPlugin )
  697.                 {
  698.                     if ( profileDB.GetProfileAlias( newUserID, profileFolder, false ) )
  699.                         SendMessageToPlugin( kNewProfileSelect, &profileFolder );
  700.                     else
  701.                         SendMessageToPlugin( kClearProfileSelect, NULL );
  702.                 }
  703.                 tempUserID = newUserID;
  704.             }
  705.             
  706.             switch ( hit )
  707.             {
  708.                 case cmd_SelectProfile:
  709.                     success = profileDB.GetProfileAlias( newUserID, profileFolder );
  710.                     if ( success )
  711.                     {
  712.                         long        err;
  713.                         err = SendMessageToPlugin( kSelectDialConfig, &profileFolder );
  714.                         if ( err == errProfileNotFound )
  715.                             SendMessageToPlugin( kEditDialConfig, &profileFolder );
  716.                     }    
  717.                     keepCounting = false;
  718.  
  719.                 break;
  720.                 
  721.                 case cmd_NewProfile:
  722.                     CStr31        profileName;
  723.                     result = NewUserProfile( profileSpec, profileFolder, profileName );
  724.                     
  725.                     if ( result == eUserCancelled )
  726.                     {
  727.                         result = eOK;
  728.                     }
  729.                     else
  730.                     {
  731.                         newUserID = profileDB.CountProfiles();
  732.                         profileDB.AddNewProfile( newUserID, profileName, profileFolder );
  733.                         
  734.                         // redraw the profile list box
  735.                         LDelRow(0, 0, listHand);
  736.                         PopulateListBox(listHand, profileDB, newUserID);
  737.                         listBox->Refresh();
  738.                         success = true;
  739.  
  740.                         // Ñ╩we ran the Profile Wizard and now we should
  741.                         // open the Edit Settings dialog for the associated
  742.                         // dial configuration
  743.                         if ( result == eRunMUC )
  744.                         {
  745.                             SendMessageToPlugin( kEditDialConfig, &profileFolder ); 
  746.                             result = eOK;
  747.                         }
  748.  
  749.                         // Ñ we ran the Profile Wizard, but we don't want to
  750.                         // associate a dialing configuration, so write out
  751.                         // an empty "Configuration" file by calling 
  752.                         // the plugin
  753.                         else if ( result == eSkipMUC )
  754.                         {
  755.                             SendMessageToPlugin( kAutoSelectDialConfig, &profileFolder );
  756.                             result = eOK;
  757.                         }
  758.                     }
  759.                     keepCounting = false;
  760.                 break;
  761.                     
  762.                 case cmd_RenameProfile:
  763.                     RenameProfile( newUserID, profileDB, cell, listHand );
  764.                     keepCounting = false;
  765.                 break;
  766.                     
  767.                 case cmd_DeleteProfile:
  768.                     DeleteProfile( newUserID, profileDB, listHand );
  769.                     listBox->Refresh();
  770.                     keepCounting = false;
  771.                 break;
  772.                     
  773.                 case cmd_QuitProfile:
  774.                     keepCounting = false;
  775.                     return eUserCancelled;
  776.                 break;    
  777.                     
  778.                 case cmd_EditDialSettings:
  779.                     if ( profileDB.GetProfileAlias( newUserID, profileFolder ) )
  780.                     {
  781.                         SendMessageToPlugin( kEditDialConfig, &profileFolder );
  782.                         tempUserID = -1;
  783.                     }
  784.                     keepCounting = false;
  785.                 break;    
  786.             }
  787.         }
  788.         Catch_ ( inErr )
  789.         {
  790.             CStr255            errStr;
  791.             GetIndString( errStr, kProfileStrings, kReadError );
  792.             ErrorManager::ErrorNotify( inErr, errStr );
  793.         }
  794.     }
  795.     
  796.     return result;
  797. }
  798.  
  799. Boolean CUserProfile::DeleteMagicProfile( FSSpec& inSpec )
  800. {
  801.     short        nextID = 0;
  802.     CStr31        profileName;
  803.     FSSpec        profileSpec;
  804.     char*        fullURL;
  805.     Boolean        found = FALSE;
  806.     
  807.     profileSpec.vRefNum = inSpec.vRefNum;
  808.     profileSpec.parID = inSpec.parID;
  809.     profileName = MAGIC_PROFILE_NAME;
  810.     LString::CopyPStr( profileName, profileSpec.name, 32 );
  811.     
  812.     CUserProfileDB        db( inSpec );
  813.     
  814.     while ( db.GetProfileName( nextID++, profileName ) )
  815.     {
  816.         if ( profileName == MAGIC_PROFILE_NAME )
  817.         {
  818.             db.DeleteProfile( --nextID );
  819.             if ( db.GetLastProfileID() == nextID )
  820.                 db.SetLastProfileID( 0 );
  821.             found = TRUE;
  822.             break;
  823.         }
  824.     }
  825.  
  826.     fullURL = CFileMgr::EncodedPathNameFromFSSpec( profileSpec, TRUE );
  827.     if ( fullURL && found )
  828.     {
  829.         XP_RemoveDirectoryRecursive( fullURL, xpURL );
  830.         XP_FREE( fullURL );
  831.     }
  832.     if ( found )
  833.         return TRUE;
  834.     return FALSE;
  835. }
  836.  
  837. void CUserProfile::PopulateListBox(ListHandle& listHand, CUserProfileDB& profileDB, short defaultID)
  838. {
  839.     LSetDrawingMode(false, listHand);
  840.  
  841.     short nextID = 0;
  842.     Cell cell;
  843.     CStr31 str;
  844.     Boolean gotOne = profileDB.GetProfileName(nextID, str);
  845.     while (gotOne) {
  846.         LAddRow(1, nextID, listHand);
  847.         SetPt(&cell, 0, nextID);
  848.         LSetCell(&str.fStr[1], str.fStr[0], cell, listHand);
  849.         gotOne = profileDB.GetProfileName(++nextID, str);
  850.     }
  851.     // Ñ╩select last user or first cell & scroll to it
  852.     SetPt(&cell, 0, defaultID);
  853.     LSetSelect(true, cell, listHand);
  854.     LAutoScroll(listHand);
  855.     LSetDrawingMode(true, listHand);
  856. }
  857.  
  858. // Ensure the requested new profile folder does not exist;
  859. // if it does, append a number to make a unique name.
  860. void CUserProfile::GetUniqueFolderName(FSSpec& folder)
  861. {
  862.     if (CFileMgr::FileExists(folder)) {
  863.         int nextIndex = 2;
  864.         CStr31 requestedName = folder.name;
  865.         if (requestedName.Length() > 28)
  866.             requestedName.Length() = 28;
  867.         CStr31 uniqueName;
  868.         do {
  869.             uniqueName = requestedName;
  870.             char suffix[3];
  871.             sprintf(suffix, "-%d", nextIndex++);
  872.             uniqueName += suffix;
  873.             LString::CopyPStr(uniqueName, folder.name, 32);
  874.         }
  875.         while (CFileMgr::FileExists(folder));
  876.     }
  877. }
  878.  
  879.  
  880. // Make one desktop icon
  881. static const kIconNameStringsListID = 9800;
  882.  
  883. static OSErr MakeOneDesktopIcon(const CStr31 &profileName, short templateNameIndex, short iconNameIndex)
  884. {
  885.     OSErr        err = noErr;
  886.     FSSpec         shortcutSpec = CPrefs::GetFilePrototype(CPrefs::RequiredGutsFolder);
  887.     FSSpec        desktopFolderSpec;
  888.     FSSpec        desktopIconSpec;
  889.     short        vRefNum;
  890.     long        folderID;
  891.     
  892.     GetIndString(shortcutSpec.name, kIconNameStringsListID, templateNameIndex);
  893.     
  894.     //find the source file
  895.     if (!CFileMgr::FileExists(shortcutSpec) || CFileMgr::IsFolder(shortcutSpec))
  896.         ThrowIfOSErr_(fnfErr);
  897.     
  898.     //check the destination
  899.     err = ::FindFolder(kOnSystemDisk, kDesktopFolderType, true,
  900.                         &vRefNum, &folderID);
  901.     ThrowIfOSErr_(err);
  902.     
  903.     err = CFileMgr::FolderSpecFromFolderID(vRefNum, folderID, desktopFolderSpec);
  904.     ThrowIfOSErr_(err);
  905.     
  906.     desktopIconSpec.parID = folderID;
  907.     desktopIconSpec.vRefNum = vRefNum;
  908.     GetIndString(desktopIconSpec.name, kIconNameStringsListID, iconNameIndex);
  909.     
  910.     //Append the profile name. We know that it does not contain colons
  911.     CStr63        iconName(desktopIconSpec.name);
  912.  
  913.     iconName += profileName;
  914.     
  915.     //Truncate the iconName if necessary to 31 chars
  916.     if (iconName.Length() > 30) {
  917.         iconName[0] = 30;
  918.         iconName[30] = '╔';
  919.     }
  920.     
  921.     LString::CopyPStr(iconName, desktopIconSpec.name, 31);
  922.     
  923.     //If there is already an icon with the same name, append the profile name
  924.     long    nextIndex = 1;
  925.     
  926.     while (CFileMgr::FileExists(desktopIconSpec))
  927.     {
  928.         CStr63     uniqueName(iconName);
  929.         char     suffix[5];
  930.         short    len;
  931.         
  932.         sprintf(suffix, "-%d", nextIndex++);
  933.         
  934.         len = 30 - strlen(suffix);
  935.         //Truncate the uniqueName if necessary
  936.         if (uniqueName.Length() > len) {
  937.             uniqueName[0] = len;
  938.             uniqueName[len] = '╔';
  939.         }
  940.         
  941.         uniqueName += suffix;
  942.         
  943.         LString::CopyPStr(uniqueName, desktopIconSpec.name, 31);
  944.     }
  945.     
  946.     //phew. now we have a unique name to copy to
  947.     err = CFileMgr::CopyFile(shortcutSpec, desktopFolderSpec, desktopIconSpec.name);
  948.     ThrowIfOSErr_(err);
  949.     
  950.     //make sure the custom icon bit is set
  951.     err = CFileMgr::SetFileFinderFlag(desktopIconSpec, kHasCustomIcon, TRUE);
  952.     ThrowIfOSErr_(err);
  953.     
  954.     //And now copy the profile name into the data fork
  955.     if (! CFileMgr::FileExists(desktopIconSpec))        //if it does not, we're in trouble
  956.         ThrowIfOSErr_(fnfErr);
  957.     
  958.     LFile    scriptFile(desktopIconSpec);
  959.  
  960.     scriptFile.OpenDataFork(fsRdWrPerm);
  961.     scriptFile.WriteDataFork((const char*)profileName, profileName.Length());
  962.     scriptFile.CloseDataFork();
  963.     
  964.     return err;
  965. }
  966.  
  967.  
  968.  
  969. // Make the desktop icons for the selected profile.
  970. // They are acually applescripts copied from the essential files
  971. // folder, with a property modified for this profile.
  972.  
  973. OSErr CUserProfile::MakeDesktopIcons(
  974.         const CStr31    &profileName,
  975.         const Boolean    wantsNavigator,
  976.         const Boolean    wantsInbox )
  977. {
  978.     OSErr        err = noErr;
  979.     
  980.     enum {    kNavShortcutName = 1, kInboxShortcutName,
  981.             kNavDesktopName, kInboxDesktopName};            //in profile.cnst
  982.  
  983.     if (wantsNavigator)
  984.         err = MakeOneDesktopIcon(profileName, kNavShortcutName, kNavDesktopName);
  985.     
  986.     if (wantsInbox)
  987.         err = MakeOneDesktopIcon(profileName, kInboxShortcutName, kInboxDesktopName);
  988.     
  989.     return err;
  990. }
  991.  
  992.  
  993. // Ñ prompts for a new user profile
  994. ProfileErr CUserProfile::NewUserProfile(
  995.     const FSSpec& profileSpec,
  996.     FSSpec& profileFolder,
  997.     CStr31& profileName,
  998.     UpgradeEnum upgrading,
  999.     const FSSpec* oldNetscapeF )
  1000. {
  1001.     Boolean                userChoseFolder = false;
  1002.     ProfileErr            result = eOK;
  1003.     
  1004.     profileFolder.vRefNum = profileSpec.vRefNum;
  1005.     profileFolder.parID = profileSpec.parID;
  1006.  
  1007.     result = NewProfileWizard( upgrading, profileName, profileSpec, 
  1008.         profileFolder, userChoseFolder );
  1009.                 
  1010.     if ( result == eUserCancelled )
  1011.         return eUserCancelled;
  1012.  
  1013.     // Ñ If the user chose a folder, see if it contains an existing
  1014.     // Preferences file.  If so, this folder becomes the new profile
  1015.     // folder; otherwise, create a new folder inside it.
  1016.     if ( userChoseFolder ) {
  1017.         long parentID;
  1018.         ThrowIfOSErr_( CFileMgr::GetFolderID(profileFolder, parentID) );
  1019.         
  1020.         FSSpec prefFile;
  1021.         prefFile.vRefNum = profileFolder.vRefNum;
  1022.         prefFile.parID = parentID;
  1023.         ::GetIndString( prefFile.name, 300, prefFileName );
  1024.         if (! CFileMgr::FileExists(prefFile)) {
  1025.             // want to create a new folder inside the selected one
  1026.             userChoseFolder = false;
  1027.             profileFolder.parID = parentID;
  1028.         }
  1029.     }
  1030.  
  1031.     // Ñ╩create a folder and return it
  1032.      if ( !userChoseFolder )
  1033.     {
  1034.         LString::CopyPStr( profileName, profileFolder.name, 32 );
  1035.         GetUniqueFolderName(profileFolder);
  1036.         
  1037.         if ( oldNetscapeF )
  1038.         {
  1039.             // Ñ╩special case: point profile to existing 3.0 Netscape ─
  1040.             CFileMgr::MakeAliasFile( profileFolder, *oldNetscapeF );
  1041.  
  1042.             profileFolder = *oldNetscapeF;            
  1043.         }
  1044.         else
  1045.         {    
  1046.             CreateDefaultProfileFolder(profileFolder);
  1047.         }
  1048.     }
  1049.     
  1050.     return result;
  1051. }
  1052.  
  1053. ProfileErr CUserProfile::NewProfileWizard(
  1054.     UpgradeEnum     upgrading,
  1055.     CStr31            &profileName, 
  1056.     const FSSpec    &profileFolder,
  1057.     FSSpec            &newProfileFolder,
  1058.     Boolean            &userChoseFolder )
  1059. {
  1060.     // Ñ if we're upgrading 3.0 prefs, we don't allow the user to change
  1061.     // the profile folder; just display & disable the default folder.
  1062.     // Otherwise, the callback fills in the user name as the profile
  1063.     // folder and lets the user edit it. (--this needs work)
  1064.     LArray            paneList( sizeof( PaneIDT ) );
  1065.  
  1066.  
  1067. #ifdef CAN_MAKE_DESKTOP_ICONS_FOR_PROFILE
  1068.     PaneIDT            normalPaneList[] = { profileIntroPane, userNamePane, profileNamePane,
  1069.                                     profileFolderPane, profileIconsPane, profileDonePane, 0 };
  1070.     PaneIDT            mucPaneList[] = { profileIntroPane, profilePEPane, userNamePane, profileNamePane,
  1071.                                     profileFolderPane, profileIconsPane, profileDonePane, 0 }; 
  1072. #else
  1073.     PaneIDT            normalPaneList[] = { profileIntroPane, userNamePane, profileNamePane,
  1074.                                     profileFolderPane, profileDonePane, 0 };
  1075.     PaneIDT            mucPaneList[] = { profileIntroPane, profilePEPane, userNamePane, profileNamePane,
  1076.                                     profileFolderPane, profileDonePane, 0 }; 
  1077. #endif
  1078.  
  1079.     PaneIDT*        tmpP;
  1080.     
  1081.     if ( !mHasConfigPlugin )
  1082.         tmpP = normalPaneList;
  1083.     else
  1084.         tmpP = mucPaneList;
  1085.  
  1086.     while ( *tmpP != 0 )
  1087.         paneList.InsertItemsAt( 1, LArray::index_Last, tmpP++ );
  1088.  
  1089.     CDialogWizardHandler        wizard( updateWizardDialog, paneList );
  1090.  
  1091.     LListener* listener = new CProfilePaneMonitor( &wizard );
  1092.     wizard.AddListener( listener );
  1093.     
  1094.     LWindow* window = wizard.GetDialog();    
  1095.     if ( upgrading == eExistingPrefs )
  1096.     {
  1097.         wizard.SetEditText( 'name', CPrefs::GetString( CPrefs::UserName ) );
  1098.         wizard.SetEditText( 'mail', CPrefs::GetString( CPrefs::UserEmail ) );
  1099.     }
  1100.     if ( upgrading != eNoUpgrade )
  1101.     {        
  1102.         LStdControl* cancel = (LStdControl*)window->FindPaneByID( 'cncl' );    
  1103.         if (cancel)
  1104.         {
  1105.             CStr31 label;
  1106.             GetIndString( label, kProfileStrings, kQuitLabel );
  1107.             cancel->SetDescriptor( label );
  1108.         }        
  1109.     }
  1110.  
  1111.     // Ñ hide "detected previous Navigator version" text if appropriate
  1112.     if ( upgrading != eExistingPrefs || CPrefs::sPrefFileVersion != 3 )
  1113.     {
  1114.         LPane* upgradeText = window->FindPaneByID( 40 );
  1115.         if ( upgradeText )
  1116.             upgradeText->Hide();
  1117.         upgradeText = window->FindPaneByID( 41 );
  1118.         if ( upgradeText )
  1119.             upgradeText->Hide();
  1120.     }
  1121.  
  1122.     FSSpec        tempFolder;
  1123.     tempFolder.vRefNum = profileFolder.vRefNum;
  1124.     tempFolder.parID = profileFolder.parID;
  1125.     LString::CopyPStr( "\p", tempFolder.name, 32 );
  1126.     
  1127.     CFilePicker* picker = (CFilePicker*)window->FindPaneByID( 'fold' );
  1128.     ThrowIfNil_( picker );
  1129.     picker->SetPickType( CFilePicker::Folders );
  1130.     picker->SetFSSpec( tempFolder, false );
  1131.     // Ñ don't allow different folder when upgrading
  1132.     if ( upgrading == eExistingPrefs ) {
  1133.         LPane* chooseBtn = picker->FindPaneByID(2);
  1134.         LPane* chooseText = window->FindPaneByID(31);
  1135.         if (chooseBtn && chooseText) {
  1136.             chooseBtn->Hide();
  1137.             chooseText->Hide();
  1138.         }
  1139.     }
  1140.     
  1141.     // show the profile wizard
  1142.     if ( wizard.DoWizard() == false )
  1143.     {
  1144.         // Ñ╩user cancelled
  1145.         delete listener;
  1146.         return eUserCancelled;
  1147.     }
  1148.     
  1149.     // copy user name & email to prefs; return profile name
  1150.     CStr255    userName;
  1151.     wizard.GetEditText( 'name', userName );
  1152.     CPrefs::SetString( userName, CPrefs::UserName );
  1153.     CStr255    emailAddr;
  1154.     wizard.GetEditText( 'mail', emailAddr );
  1155.     CPrefs::SetString( emailAddr, CPrefs::UserEmail );
  1156.     
  1157.     wizard.GetEditText( 'pnam', profileName );
  1158.     StripColons(profileName);
  1159.     
  1160. #ifdef CAN_MAKE_DESKTOP_ICONS_FOR_PROFILE
  1161.     // make the desktop icons
  1162.     OSErr err = MakeDesktopIcons(profileName, wizard.GetCheckboxValue('navb'), wizard.GetCheckboxValue('inbb'));
  1163.     ThrowIfOSErr_(err);        //should we do this?
  1164. #endif // CAN_MAKE_DESKTOP_ICONS_FOR_PROFILE
  1165.     
  1166.     if ( picker->WasSet() )
  1167.     {
  1168.         userChoseFolder = true;
  1169.         CFileMgr::CopyFSSpec( picker->GetFSSpec(), newProfileFolder );
  1170.     }
  1171.     
  1172.     delete listener;
  1173.  
  1174.     if ( mHasConfigPlugin )
  1175.     {
  1176.         LControl*    radioNew = (LControl*)window->FindPaneByID( 'Rnew' );
  1177.         LControl*    radioExs = (LControl*)window->FindPaneByID( 'Rexs' );
  1178.  
  1179.         if ( ( radioNew && radioNew->GetValue() ) || upgrading != eNoUpgrade )
  1180.             return eRunAccountSetup;
  1181.         else if ( radioExs && radioExs->GetValue() /* ( upgrading != eNoUpgrade ) */)
  1182.             return eRunMUC;
  1183.         return eSkipMUC;
  1184.     }
  1185.     
  1186.     return eOK;
  1187. }
  1188.  
  1189. void CUserProfile::RenameProfile(short selectedID, CUserProfileDB& profileDB,
  1190.     Cell& cell, ListHandle& listHand)
  1191. {
  1192.     CStr31 newName;
  1193.     if (profileDB.GetProfileName(selectedID, newName) == false)
  1194.         return;
  1195.  
  1196.     CStr255 prompt;
  1197.     GetIndString(prompt, kProfileStrings, kRenamePrompt);
  1198.  
  1199.     Boolean ok = UStdDialogs::AskStandardTextPrompt(nil, prompt, newName,
  1200.         NULL, NULL, kStr31Len);
  1201.  
  1202.     if (ok && newName.Length() > 0) {
  1203.         LSetCell(&newName.fStr[1], newName.Length(), cell, listHand);
  1204.  
  1205.         profileDB.SetProfileName(selectedID, newName);
  1206.     }
  1207. }
  1208.  
  1209. void CUserProfile::DeleteProfile(short selectedID, CUserProfileDB& profileDB, ListHandle& listHand)
  1210. {
  1211.     CStr255 prompt;
  1212.     GetIndString(prompt, kProfileStrings, kDeletePrompt);
  1213.     if (ErrorManager::PlainConfirm(prompt))
  1214.     {
  1215.         profileDB.DeleteProfile(selectedID);
  1216.  
  1217.         if (--selectedID < 0)
  1218.             selectedID = 0;
  1219.         
  1220.         // redraw the profile list box
  1221.         LDelRow(0, 0, listHand);
  1222.  
  1223.         PopulateListBox(listHand, profileDB, selectedID);
  1224.     }
  1225. }
  1226.  
  1227. // Ñ Reflects profile name & path into xp preferences for querying by PE;
  1228. // also registers a callback so changing the name renames the profile.
  1229. // if we don't know how many profiles we have, pass -1 and the numprofiles
  1230. // pref will not be set (nasty hack: see CPrefs::InitPrefsFolder())
  1231. void
  1232. CUserProfile::ReflectToPreferences(const CStr31& profileName,
  1233.     const FSSpec& profileFolder, short numProfiles)
  1234. {
  1235.     char* folderPath = CFileMgr::EncodedPathNameFromFSSpec( profileFolder, true );
  1236.     if ( folderPath )
  1237.     {
  1238.         PREF_SetDefaultCharPref( "profile.directory", folderPath );
  1239.         free( folderPath );
  1240.     }
  1241.     
  1242.     PREF_SetDefaultCharPref( "profile.name", profileName );
  1243.     
  1244.     if (numProfiles > -1)
  1245.         PREF_SetDefaultIntPref( "profile.numprofiles", numProfiles );
  1246.     
  1247.     PREF_RegisterCallback( "profile.name", ProfilePrefChangedFunc, NULL );
  1248. }
  1249.  
  1250. // Ñ If a Defaults folder exists in Essential Files, copy it into
  1251. // Netscape Users and rename it to the selected profile name.
  1252. // Otherwise, or in case of a copying error, create a new folder.
  1253. void CUserProfile::CreateDefaultProfileFolder(const FSSpec& profileFolder)
  1254. {
  1255.     OSErr err = noErr;
  1256.     Boolean needToCreate = true;
  1257.     
  1258.     FSSpec usersFolder;
  1259.     CFileMgr::FolderSpecFromFolderID(profileFolder.vRefNum,
  1260.         profileFolder.parID, usersFolder);
  1261.     
  1262.     FSSpec templateFolder = CPrefs::GetFilePrototype(CPrefs::RequiredGutsFolder);
  1263.     GetIndString( templateFolder.name, 300, profileTemplateDir );
  1264.  
  1265.     if (CFileMgr::FileExists(templateFolder))
  1266.     {
  1267.         err = FSpDirectoryCopy( &templateFolder, &usersFolder,
  1268.             nil, 0, true, nil );
  1269.         
  1270.         if (err == noErr) {
  1271.             needToCreate = false;
  1272.             
  1273.             err = HRename(profileFolder.vRefNum, profileFolder.parID,
  1274.                 templateFolder.name, profileFolder.name);
  1275.         }
  1276.     }
  1277.     
  1278.     if (needToCreate) {
  1279.         short        newRefNum;
  1280.         long        newParID;
  1281.         err = CFileMgr::CreateFolderInFolder(
  1282.                         profileFolder.vRefNum, profileFolder.parID,
  1283.                         profileFolder.name, &newRefNum, &newParID );
  1284.     }
  1285.     
  1286.     ThrowIfOSErr_( err ); 
  1287. }
  1288.  
  1289. // Ñ╩find the network configuration plugin and return a function ptr.
  1290. // to it's only entry point if possible
  1291. void* CUserProfile::LoadConfigPlugin()
  1292. {
  1293.         // BULLSHIT ALERT: Get out if I can't call GetSharedLibrary.
  1294.         //    Future: do the right thing for 68K.  See bug#56245
  1295.     long sSysArchitecture = 0;
  1296.     if ( (Gestalt(gestaltSysArchitecture, &sSysArchitecture) != noErr)
  1297.         || (sSysArchitecture != gestaltPowerPC) )
  1298.         {
  1299.                 // Can't determine what we _do_ have, or we determined that it's _not_ PPC...
  1300.             return NULL;
  1301.         }
  1302.  
  1303.     Ptr                    main;
  1304.     Str255                errName;
  1305.     PE_PluginFuncType    pluginFunc;
  1306.  
  1307.     OSErr err = ::GetSharedLibrary( "\pMUP", kPowerPCCFragArch, kFindCFrag, &mConfigPluginID,
  1308.             &main, errName );
  1309.     if ( err != noErr )
  1310.     { 
  1311.         err = ::GetSharedLibrary( "\pMUP", kPowerPCCFragArch, kLoadCFrag, &mConfigPluginID,
  1312.                 &main, errName );
  1313.     }
  1314.     if ( err == noErr )
  1315.     {    
  1316.         CFragSymbolClass    dontCare;
  1317.         mPluginLoaded = TRUE;
  1318.         err = ::FindSymbol( mConfigPluginID, "\pPE_PluginFunc", (Ptr*)&pluginFunc, &dontCare );
  1319.     }
  1320.     
  1321.     if ( err == noErr )
  1322.         return pluginFunc;
  1323.     return NULL;
  1324. }
  1325.  
  1326. // Ñ╩close the connection to the configuration plugin
  1327. OSErr CUserProfile::CloseConfigPlugin()
  1328. {
  1329. //    if ( mPluginLoaded )
  1330. //        return CloseConnection( &mConfigPluginID );
  1331.     return noErr;
  1332. }
  1333.  
  1334. long CUserProfile::SendMessageToPlugin( long selector, void* pb )
  1335. {
  1336.     OSErr                err;
  1337.     PE_PluginFuncType    pluginFunc;
  1338.     
  1339.     if ( !mHasConfigPlugin )
  1340.         return -1;
  1341.         
  1342.     pluginFunc = (PE_PluginFuncType)LoadConfigPlugin();            
  1343.     if ( pluginFunc )
  1344.     {
  1345.         union {
  1346.         char                buffer[ 1024 ];
  1347.         MUCInfo                mucInfo;
  1348.         } tmp;
  1349.         
  1350.         // Ñ╩call the stub to have it switch all the local machine
  1351.         //        stuff to use this user's configuration
  1352.         err = (*pluginFunc)( selector, pb, tmp.buffer );
  1353.         CloseConfigPlugin();
  1354.  
  1355. //        if ( err == noErr && selector == kGetDialConfig )
  1356. //        {
  1357. //            cstring        descString;
  1358. //            PrettyPrintConfiguration( mucInfo, descString );
  1359. //            inCaption->SetDescriptor( (CStr255)(char*)descString );
  1360. //        }
  1361.         return noErr;
  1362.     }
  1363.     return noErr;
  1364. }
  1365.  
  1366. /*****************************************************************************
  1367. */
  1368. CUserProfileDB::CUserProfileDB( FSSpec& spec, Boolean createIt ): fFile( spec )
  1369. {
  1370.     if ( createIt )
  1371.     {
  1372.         Try_
  1373.         {
  1374.             fFile.CreateNewFile( emSignature, 'PRFL' );        // ?? file type?
  1375.         }
  1376.         Catch_( inErr )
  1377.         {
  1378.             if ( inErr == dupFNErr )
  1379.                 ;
  1380.             else
  1381.                 Throw_( inErr );
  1382.         }
  1383.     }
  1384.     fFile.OpenResourceFork( fsRdWrPerm );
  1385. }
  1386.  
  1387. short CUserProfileDB::CountProfiles()
  1388. {
  1389.     return ::Count1Resources('STR ');
  1390. }
  1391.  
  1392. short CUserProfileDB::GetNextProfileID()
  1393. {
  1394.     short nextUserID = CountProfiles();
  1395.     
  1396.     return nextUserID;
  1397. }
  1398.  
  1399. short CUserProfileDB::GetProfileIDByUsername(const CString& username)
  1400. {
  1401.     int                    id = kFirstProfileID, returnID = -1;
  1402.     Handle                hProfileData = GetDBResource('DATA', id);
  1403.     ProfileDataHeader    *pHeader;    
  1404.     char                *profileUser;
  1405.                 
  1406.     while (hProfileData && (returnID == -1)) {
  1407.         HLock(hProfileData);
  1408.         pHeader = (ProfileDataHeader *) *hProfileData;
  1409.             
  1410.         profileUser = ((char *) pHeader) + pHeader->firstOffset;
  1411.         
  1412.         if (username == profileUser) {
  1413.             returnID = id - kFirstProfileID;
  1414.         }
  1415.         
  1416.         HUnlock(hProfileData);
  1417.  
  1418.         hProfileData = GetDBResource('DATA', ++id);
  1419.         
  1420.     }
  1421.  
  1422.     return returnID;
  1423. }
  1424.  
  1425. short CUserProfileDB::GetProfileIDByEmail(const CString& emailAddr)
  1426. {
  1427.     int                    id = kFirstProfileID, returnID = -1;
  1428.     Handle                hProfileData = GetDBResource('DATA', id);
  1429.     ProfileDataHeader    *pHeader;    
  1430.     char                *profileEmail;
  1431.                 
  1432.     while (hProfileData && (returnID == -1)) {
  1433.         HLock(hProfileData);
  1434.         pHeader = (ProfileDataHeader *) *hProfileData;
  1435.             
  1436.         profileEmail = ((char *) pHeader) + pHeader->firstOffset
  1437.             + pHeader->nameLength;
  1438.         
  1439.         if (emailAddr == profileEmail) {
  1440.             returnID = id - kFirstProfileID;
  1441.         }
  1442.         
  1443.         HUnlock(hProfileData);
  1444.  
  1445.         hProfileData = GetDBResource('DATA', ++id);
  1446.         
  1447.     }
  1448.  
  1449.     return returnID;
  1450. }
  1451.  
  1452. short CUserProfileDB::GetLastProfileID()
  1453. {
  1454.     short lastUserID = kFirstProfileID;
  1455.     short nextUserID = kFirstProfileID + GetNextProfileID();
  1456.  
  1457.     // ID of the previous user is stored as a resource
  1458.     Handle lastUser = GetDBResource('user', kFirstProfileID);
  1459.     if (lastUser) {
  1460.         lastUserID = **(short **) lastUser;
  1461.         if (lastUserID >= nextUserID)
  1462.             lastUserID = kFirstProfileID;
  1463.         ::ReleaseResource(lastUser);
  1464.     }
  1465.     
  1466.     return lastUserID - kFirstProfileID;
  1467. }
  1468.  
  1469. void CUserProfileDB::SetLastProfileID(short newUserID)
  1470. {
  1471.     newUserID += kFirstProfileID;
  1472.     Handle lastUser = GetDBResource('user', kFirstProfileID);
  1473.     if (!lastUser) {
  1474.         PtrToHand(&newUserID, &lastUser, sizeof(short));
  1475.         ::AddResource(lastUser, 'user', kFirstProfileID, nil);
  1476.     }
  1477.     else {
  1478.         BlockMove(&newUserID, *lastUser, sizeof(short));
  1479.         ::ChangedResource(lastUser);
  1480.         ::ReleaseResource(lastUser);
  1481.     }
  1482. }
  1483.  
  1484. void CUserProfileDB::AddNewProfile(short id, const CStr31& profileName, const FSSpec& profileFolder)
  1485. {
  1486.     id += kFirstProfileID;
  1487.     // create new STR, alis, and DATA resources
  1488.     StringHandle nameHand;
  1489.     PtrToHand(profileName, &(Handle) nameHand, profileName.Length() + 1);
  1490.     AddResource((Handle) nameHand, 'STR ', id, nil);
  1491.  
  1492.     AliasHandle alias;
  1493.     OSErr err = NewAlias( nil, &profileFolder, &alias );
  1494.     if (err == noErr) {
  1495.         AddResource((Handle) alias, 'alis', id, profileFolder.name);
  1496.     }
  1497.  
  1498.     SetProfileData(id - kFirstProfileID);
  1499. }
  1500.  
  1501. Boolean CUserProfileDB::GetProfileName(short id, CStr31& name)
  1502. {
  1503.     // -- use Get1Resource instead of GetString to avoid grabbing 
  1504.     // spurious strings from other programs (e.g. Kaleidoscope)
  1505.     StringHandle strHand = (StringHandle) GetDBResource('STR ', id + kFirstProfileID);
  1506.     if (strHand == nil)
  1507.         return false;
  1508.  
  1509.     HLock((Handle) strHand);
  1510.     int len = *strHand[0] + 1;
  1511.     if (len > 32) len = 32;
  1512.     BlockMove(*strHand, name.fStr, len);
  1513.     name.Length() = len - 1;
  1514.     HUnlock((Handle) strHand);
  1515.     
  1516.     ReleaseResource((Handle) strHand);
  1517.     return true;
  1518. }
  1519.  
  1520. void CUserProfileDB::SetProfileName(short id, const CStr31& name)
  1521. {
  1522.     StringHandle strHand = (StringHandle) GetDBResource('STR ', id + kFirstProfileID);
  1523.     if (strHand) {
  1524.         SetString(strHand, name);
  1525.         ChangedResource((Handle) strHand);
  1526.         ReleaseResource((Handle) strHand);
  1527.     }
  1528. }
  1529.  
  1530. void CUserProfileDB::SetProfileData(short id)
  1531. {
  1532.     Handle                hProfileData;
  1533.     ProfileDataHeader    profileHeader;
  1534.     short int            dataLength;
  1535.     long int            dataOffset;
  1536.     CStr255                userName;
  1537.     CStr255                emailName;
  1538.     XP_Bool                addResource = false;
  1539.  
  1540.     id += kFirstProfileID;        // In order to allow this method to be called from
  1541.                                 // outside the class, we have to allow the value in to
  1542.                                 // be a "raw" profile number (i.e., as returned by
  1543.                                 // GetLastProfile);
  1544.     
  1545.     emailName = CPrefs::GetString(CPrefs::UserEmail);
  1546.     userName = CPrefs::GetString(CPrefs::UserName);
  1547.     
  1548.     profileHeader.count = 2;
  1549.     profileHeader.firstOffset = sizeof(ProfileDataHeader);
  1550.  
  1551.     /* (the +1 is for the  null terminator for each string) */
  1552.     profileHeader.nameLength = userName.Length() + 1;
  1553.     profileHeader.emailLength = emailName.Length() + 1;
  1554.     
  1555.     /* First, compute the length of the resource */
  1556.     dataLength = sizeof(ProfileDataHeader) + profileHeader.nameLength + profileHeader.emailLength;
  1557.     
  1558.     /* See if we're replacing or adding */
  1559.     hProfileData = GetDBResource('DATA', id);
  1560.     
  1561.     if (hProfileData) {
  1562.         SetHandleSize(hProfileData, dataLength);
  1563.         if (MemError() == noErr) {
  1564.             XP_MEMSET(*hProfileData, '\0', dataLength);
  1565.         } else {
  1566.             ReleaseResource(hProfileData);
  1567.             hProfileData = nil;
  1568.         }
  1569.     } else {
  1570.         hProfileData = NewHandleClear(dataLength);
  1571.         addResource = true;
  1572.     }
  1573.     
  1574.     if (hProfileData) {
  1575.         dataOffset = 0;
  1576.         
  1577.         HLock((Handle) hProfileData);
  1578.         
  1579.         BlockMove(&profileHeader, *hProfileData, sizeof(ProfileDataHeader));
  1580.         
  1581.         dataOffset = sizeof(ProfileDataHeader);
  1582.         BlockMove(&(userName.fStr[1]), ((unsigned char *) *hProfileData) + dataOffset,    
  1583.             profileHeader.nameLength-1);
  1584.         
  1585.         dataOffset += profileHeader.nameLength;
  1586.         BlockMove(&(emailName.fStr[1]), ((unsigned char *) *hProfileData) + dataOffset,    
  1587.             profileHeader.emailLength-1);
  1588.  
  1589.         HUnlock((Handle) hProfileData);
  1590.  
  1591.         if (addResource) {
  1592.             ::AddResource(hProfileData, 'DATA', id, nil);
  1593.         } else {
  1594.             ::ChangedResource(hProfileData);
  1595.             ::ReleaseResource(hProfileData);
  1596.         }
  1597.     }    
  1598. }
  1599.  
  1600. Boolean CUserProfileDB::GetProfileAlias(short id, FSSpec& profileFolder, Boolean allowUserInteraction )
  1601. {
  1602.     Boolean success = true;
  1603.     AliasHandle a;
  1604.     a = (AliasHandle) GetDBResource('alis', id + kFirstProfileID);
  1605.     ThrowIfNil_(a);
  1606.     
  1607.     Boolean        changed;
  1608.     OSErr        err;
  1609.     
  1610.     if ( allowUserInteraction )
  1611.     {
  1612.         err = ResolveAlias( NULL, a, &profileFolder, &changed );
  1613.  
  1614.         // If the alias couldn't be resolved, give the user 
  1615.         // a chance to locate the profile folder
  1616.         if (err < 0) {
  1617.             success = false;
  1618.             CStr255 errStr;
  1619.             CStr31    profileName;
  1620.             GetIndString(errStr, CUserProfile::kProfileStrings, CUserProfile::kBadAliasError);
  1621.             GetProfileName(id, profileName);
  1622.             StringParamText(errStr, profileName);
  1623.             
  1624.             if (ErrorManager::PlainConfirm(errStr))
  1625.             {
  1626.                 StandardFileReply reply;
  1627.                 reply.sfFile = CPrefs::GetFilePrototype(CPrefs::UsersFolder);
  1628.                 if ( CFilePicker::DoCustomGetFile(reply, CFilePicker::Folders, true) )
  1629.                 {
  1630.                     CFileMgr::CopyFSSpec(reply.sfFile, profileFolder);
  1631.                     Boolean changed;
  1632.                     err = UpdateAlias(nil, &reply.sfFile, a, &changed);
  1633.                     ThrowIfOSErr_(err);
  1634.                     ChangedResource((Handle) a);
  1635.                     success = true;
  1636.                 }
  1637.             }
  1638.         }
  1639.     }
  1640.     else
  1641.     {
  1642.         short    aliasCount = 1;
  1643.         
  1644.         err = MatchAlias( NULL, kARMMountVol | kARMNoUI | kARMMultVols | kARMSearch | kARMSearchMore,
  1645.             a, &aliasCount, &profileFolder, &changed, NULL, NULL );
  1646.         if ( err < 0 )
  1647.             success = false;
  1648.     }
  1649.  
  1650.     ReleaseResource((Handle) a);
  1651.     
  1652.     return success;
  1653. }
  1654.  
  1655. // This will change the value of selectedID if it becomes out of bounds
  1656. void CUserProfileDB::DeleteProfile(short selectedID)
  1657. {
  1658.     selectedID += kFirstProfileID;
  1659.     // delete profile resources and move the subsequent 
  1660.     // resources down to fill the space
  1661.     Handle toDelete = GetDBResource('STR ', selectedID);
  1662.     if (toDelete)
  1663.         RemoveResource(toDelete);
  1664.     toDelete = GetDBResource('alis', selectedID);
  1665.     if (toDelete)
  1666.         RemoveResource(toDelete);
  1667.     
  1668.     toDelete = GetDBResource('DATA', selectedID);
  1669.     if (toDelete)
  1670.         RemoveResource(toDelete);
  1671.     
  1672.     int id = selectedID + 1;
  1673.     Handle next = GetDBResource('STR ', id);
  1674.     while (next) {
  1675.         ::SetResInfo(next, id - 1, nil);
  1676.  
  1677.         next = GetDBResource('DATA', id);
  1678.         if (next) {
  1679.             ::SetResInfo(next, id - 1, nil);
  1680.             ReleaseResource(next);
  1681.         }
  1682.         
  1683.         next = GetDBResource('alis', id);
  1684.         if (next) {
  1685.             ::SetResInfo(next, id - 1, nil);
  1686.             ReleaseResource(next);
  1687.         }
  1688.         // don't need to release strings because Populate uses them
  1689.         next = GetDBResource('STR ', ++id);
  1690.     }
  1691. }
  1692.  
  1693. Handle CUserProfileDB::GetDBResource(ResType theType, short theID)
  1694. {
  1695.     StUseResFile resFile( fFile.GetResourceForkRefNum() );
  1696.     
  1697.     return ::Get1Resource(theType, theID);
  1698. }
  1699.  
  1700.  
  1701. /*****************************************************************************
  1702. */
  1703. const int cmd_NextPane = 8000;
  1704. const int cmd_PrevPane = 8001;
  1705.  
  1706. CProfilePaneMonitor::CProfilePaneMonitor( CDialogWizardHandler* wizard )
  1707. {
  1708.     fWizard = wizard;
  1709.     fCopiedName = false;
  1710. }
  1711.  
  1712. // !! This needs some work.
  1713. void CProfilePaneMonitor::ListenToMessage( MessageT inMessage, void* /* ioParam */)
  1714. {
  1715.     PaneIDT            nameField;
  1716.     Boolean            onNameField = false;
  1717.     LView*            window;
  1718.     
  1719.     window = fWizard->GetDialog();
  1720.  
  1721.     LStdControl*    next = (LStdControl*)window->FindPaneByID( 'ok  ' );
  1722.     LStdControl*    back = (LStdControl*)window->FindPaneByID( 'back' );
  1723.     CStr255            buttonTitle;
  1724.     
  1725.     if (fWizard->CurrentPane() == userNamePane) {
  1726.         nameField = 'name';
  1727.         onNameField = true;
  1728.     }
  1729.     else if (fWizard->CurrentPane() == profileNamePane) {
  1730.         nameField = 'pnam';
  1731.         onNameField = true;
  1732.     }
  1733.  
  1734.     if ( next && ( inMessage == cmd_NextPane || inMessage == cmd_PrevPane ) )
  1735.     {
  1736.         if ( fWizard->CurrentPaneNumber() == fWizard->TotalPanes() )
  1737.         {
  1738.             LControl*    radioNew = (LControl*)window->FindPaneByID( 'Rnew' );
  1739.             LControl*    radioExs = (LControl*)window->FindPaneByID( 'Rexs' );
  1740.             LPane*        vnorm = (LView*)window->FindPaneByID('Vnor');
  1741.             LPane*        vexs = (LView*)window->FindPaneByID('Vexs');
  1742.             LPane*        vnew = (LView*)window->FindPaneByID('Vnew');
  1743.             
  1744.             vnorm->Hide();
  1745.             vexs->Hide();
  1746.             vnew->Hide();
  1747.             if ( radioExs && radioExs->GetValue() )
  1748.             {
  1749.                 GetIndString( buttonTitle, CUserProfile::kProfileStrings, CUserProfile::kCreateProfileLabel );
  1750.                 vexs->Show();
  1751.             }
  1752.             else if ( radioNew && radioNew->GetValue() )
  1753.             {
  1754.                 //GetIndString( buttonTitle, CUserProfile::kProfileStrings, CUserProfile::kDoneLabel );
  1755.                 GetIndString( buttonTitle, CUserProfile::kProfileStrings, CUserProfile::kRunASLabel );
  1756.                 vnew->Show();
  1757.             }
  1758.             else
  1759.             {
  1760.                 GetIndString( buttonTitle, CUserProfile::kProfileStrings, CUserProfile::kDoneLabel );
  1761.                 vnorm->Show();
  1762.             }
  1763.             next->SetDescriptor( buttonTitle );
  1764.         }
  1765.         else
  1766.         {
  1767.             GetIndString( buttonTitle, CUserProfile::kProfileStrings, CUserProfile::kNextLabel );
  1768.             next->SetDescriptor( buttonTitle );
  1769.         }
  1770.     }
  1771.  
  1772.     if ( back && ( inMessage == cmd_NextPane || inMessage == cmd_PrevPane ) )
  1773.     {
  1774.         if ( fWizard->CurrentPaneNumber() == LArray::index_First )
  1775.             back->Disable();
  1776.         else
  1777.             back->Enable();
  1778.     }
  1779.  
  1780.  
  1781.     // copy profile name to folder name, unless the user has changed
  1782.     // the path or we're creating the default profile
  1783.     if ( inMessage == cmd_NextPane && fWizard->CurrentPane() == profileFolderPane )
  1784.     {
  1785.         CStr31 profileName;
  1786.         fWizard->GetEditText('pnam', profileName);
  1787.         StripColons(profileName);
  1788.         CFilePicker* picker = (CFilePicker*) fWizard->GetDialog()->FindPaneByID('fold');
  1789.         if (picker && !picker->WasSet()) {
  1790.             FSSpec folder = picker->GetFSSpec();
  1791.             LString::CopyPStr(profileName, folder.name, 32);
  1792.             
  1793.             CUserProfile::GetUniqueFolderName(folder);
  1794.             picker->SetFSSpec(folder, false);
  1795.         }
  1796.     }
  1797.     // copy user name to profile name (only do this once)
  1798.     else if ( inMessage == cmd_NextPane && fWizard->CurrentPane() == profileNamePane 
  1799.               && !fCopiedName)
  1800.     {
  1801.         CStr31 profileName;
  1802.         fWizard->GetEditText('name', profileName);
  1803.         StripColons(profileName);
  1804.         if (profileName.Length() > kStr31Len)
  1805.             profileName.Length() = kStr31Len;
  1806.         fWizard->SetEditText('pnam', profileName);
  1807.         fCopiedName = true;
  1808.     }
  1809.  
  1810.     // select Name field
  1811.     if (onNameField && (inMessage == cmd_NextPane || inMessage == cmd_PrevPane)) {
  1812.         LEditField* field = (LEditField*) fWizard->GetDialog()->FindPaneByID(nameField);
  1813.         if (field) {
  1814.             field->SwitchTarget(field);
  1815.             field->SelectAll();
  1816.         }
  1817.     }
  1818.  
  1819.     // disable Next button if user hasn't entered name
  1820.     if (onNameField)
  1821.     {
  1822.         CStr255 text;
  1823.         fWizard->GetEditText( nameField, text );
  1824.         if ( text.Length() == 0 )
  1825.             fWizard->DisableNextButton();
  1826.         else
  1827.             fWizard->EnableNextButton();
  1828.     }
  1829.     else
  1830.         fWizard->EnableNextButton();
  1831. }
  1832.  
  1833. /*****************************************************************************
  1834. */
  1835.  
  1836. CDialogWizardHandler::CDialogWizardHandler( ResIDT dlogID, LArray& paneList ):
  1837.     fDialog( dlogID, CFrontApp::GetApplication() ), fPaneList( paneList )
  1838. {
  1839.     ArrayIndexT        index;
  1840.     PaneIDT            paneID;
  1841.     LView*            pane;
  1842.     
  1843.     index = LArray::index_First;
  1844.  
  1845.     fCurrentPane = LArray::index_First;
  1846.     fListener = nil;
  1847.     
  1848.     LWindow* window = fDialog.GetDialog();
  1849.     ThrowIfNil_( window );
  1850.  
  1851.     for ( index = LArray::index_First; index <= fPaneList.GetCount(); index++ )
  1852.     {
  1853.         fPaneList.FetchItemAt( index, &paneID );
  1854.         LView::SetDefaultView( window );
  1855.         if ( GetResource( 'PPob', paneID ) == nil )
  1856.             break;
  1857.         pane = (LView*)UReanimator::ReadObjects( 'PPob', paneID );
  1858.         if ( pane )
  1859.         {
  1860.             if ( index != LArray::index_First )
  1861.                 pane->Hide();
  1862.             pane->Enable();
  1863.             pane->FinishCreate();
  1864.         }
  1865.     }
  1866. }
  1867.  
  1868. PaneIDT CDialogWizardHandler::CurrentPane()
  1869. {
  1870.     PaneIDT        paneID;
  1871.     fPaneList.FetchItemAt( fCurrentPane, &paneID );
  1872.     return paneID;
  1873. }
  1874.  
  1875. ArrayIndexT CDialogWizardHandler::CurrentPaneNumber()
  1876. {
  1877.     return fCurrentPane;
  1878. }
  1879.  
  1880. ArrayIndexT CDialogWizardHandler::TotalPanes()
  1881. {
  1882.     return fPaneList.GetCount();
  1883. }
  1884.  
  1885. void CDialogWizardHandler::AddListener(LListener* st)
  1886. {
  1887.     fListener = st;
  1888. }
  1889.  
  1890. Boolean CDialogWizardHandler::DoWizard()
  1891. {
  1892.     Boolean cancelled = false;
  1893.     LWindow* window = fDialog.GetDialog();
  1894.     ShowPane( fCurrentPane, window );
  1895.     
  1896.     Boolean done = false;
  1897.     while ( !done )
  1898.     {
  1899.         MessageT hit = fDialog.DoDialog();
  1900.             
  1901.         switch ( hit )
  1902.         {
  1903.             case cmd_NextPane:
  1904.                 done = ShowPane( fCurrentPane + 1, window );
  1905.             break;
  1906.             
  1907.             case cmd_PrevPane:
  1908.                 done = ShowPane( fCurrentPane - 1, window );
  1909.             break;
  1910.             
  1911.             case msg_Cancel:
  1912.                 cancelled = done = true;
  1913.             break;
  1914.         }
  1915.         if ( !done && fListener )
  1916.             fListener->ListenToMessage( hit, nil );
  1917.     }
  1918.     return !cancelled;
  1919. }
  1920.  
  1921. Boolean CDialogWizardHandler::ShowPane( ArrayIndexT paneNum, LWindow* window )
  1922. {
  1923.     PaneIDT        paneID;
  1924.     
  1925.     if ( paneNum < LArray::index_First )
  1926.         return false;
  1927.     
  1928.     if ( paneNum != fCurrentPane )
  1929.     {
  1930.         fPaneList.FetchItemAt( fCurrentPane, &paneID );
  1931.         LPane* pane = window->FindPaneByID( paneID );
  1932.         if ( pane )
  1933.             pane->Hide();
  1934.     }
  1935.         
  1936.     fCurrentPane = paneNum;
  1937.     if ( paneNum > fPaneList.GetCount() )
  1938.         return true;
  1939.     fPaneList.FetchItemAt( paneNum, &paneID );
  1940.     LPane* pane = window->FindPaneByID( paneID );
  1941.     if ( pane )
  1942.         pane->Show();
  1943.  
  1944.     return false;
  1945. }
  1946.  
  1947. void CDialogWizardHandler::EnableNextButton()
  1948. {
  1949.     LWindow*    window = fDialog.GetDialog();
  1950.     if ( window )
  1951.     {
  1952.         LStdControl* next = (LStdControl*)window->FindPaneByID( 'ok  ' );
  1953.         if ( next )
  1954.             next->Enable();
  1955.     }
  1956. }
  1957.     
  1958. void CDialogWizardHandler::DisableNextButton()
  1959. {
  1960.     LWindow*    window = fDialog.GetDialog();
  1961.     if ( window )
  1962.     {
  1963.         LStdControl* next = (LStdControl*)window->FindPaneByID( 'ok  ' );
  1964.         if ( next )
  1965.             next->Disable();
  1966.     }
  1967. }
  1968.  
  1969. LWindow* CDialogWizardHandler::GetDialog()
  1970. {
  1971.     return fDialog.GetDialog();
  1972. }
  1973.  
  1974. void CDialogWizardHandler::SetEditText(PaneIDT paneID, const CString& text)
  1975. {
  1976.     LWindow* window = fDialog.GetDialog();
  1977.     if (window) {
  1978.         LEditField* field = (LEditField*) window->FindPaneByID(paneID);
  1979.         if (field) {
  1980.             field->SetDescriptor(text);
  1981.         }
  1982.     }
  1983. }
  1984.  
  1985. void CDialogWizardHandler::GetEditText(PaneIDT paneID, CString& text)
  1986. {
  1987.     LWindow* window = fDialog.GetDialog();
  1988.     if (window) {
  1989.         LEditField* field = (LEditField*) window->FindPaneByID(paneID);
  1990.         if (field) {
  1991.             field->GetDescriptor(text);
  1992.         }
  1993.     }
  1994. }
  1995.  
  1996. void CDialogWizardHandler::SetCheckboxValue(PaneIDT paneID, const Boolean value)
  1997. {
  1998.     LWindow* window = fDialog.GetDialog();
  1999.     if (window) {
  2000.         LControl* checkbox = (LControl*) window->FindPaneByID(paneID);
  2001.         if (checkbox) {
  2002.             checkbox->SetValue((Int32)value);
  2003.         }
  2004.     }
  2005. }
  2006.  
  2007. Boolean CDialogWizardHandler::GetCheckboxValue(PaneIDT paneID)
  2008. {
  2009.     LWindow* window = fDialog.GetDialog();
  2010.     if (window) {
  2011.         LControl* checkbox = (LControl*) window->FindPaneByID(paneID);
  2012.         if (checkbox) {
  2013.             return (Boolean)checkbox->GetValue();
  2014.         }
  2015.     }
  2016.     
  2017.     return -1;
  2018. }
  2019.  
  2020.