text: 
  /****************************************************************************\
  
      SAVEAS.C / OPK Wizard (OPKWIZ.EXE)
  
      Microsoft Confidential
      Copyright (c) Microsoft Corporation 1998
      All rights reserved
  
      Source file for the OPK Wizard that contains the external and internal
      functions used by the "saveas / save" wizard page.
  
      09/2000 - Stephen Lodwick (STELO)
          Ported OPK Wizard to Whistler
  
  \****************************************************************************/
  
  
  //
  // Include File(s):
  //
  
  #include "pch.h"
  #include "wizard.h"
  #include "resource.h"
  #include "appinst.h"
  
  
  //
  // Internal Define(s):
  //
  
  #define MAX_CONFIG_NAME 32
  
  #define DIR_SBSI        _T("sbsi")
  #define DIR_SBSI_SETUP  _T("setup")
  #define FILE_SBSI_SETUP _T("setup.exe")
  #define CMD_SBSI_SETUP  _T("-SMS -S -f1\"%s\\silent.iss\"")
  
  
  //
  // Internal Function Prototype(s):
  //
  
  static BOOL OnInit(HWND, HWND, LPARAM);
  static BOOL OnSave(HWND);
  
  static BOOL AddSbsiInstall(LPTSTR lpszShare);
  
  
  //
  // External Function(s):
  //
  
  LRESULT CALLBACK SaveAsDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  {
      switch (uMsg)
      {
          HANDLE_MSG(hwnd, WM_INITDIALOG, OnInit);
  
          case WM_COMMAND:
  
              switch ( LOWORD(wParam) )
              {
                  case IDOK:
                      if ( OnSave(hwnd))
                          EndDialog(hwnd, TRUE);
                      
                      break;
  
                  case IDCANCEL:
                      EndDialog(hwnd, FALSE);
                      break;
              }
              return FALSE;
          default:
              return FALSE;
      }
  
      return TRUE;
  }
  
  
  //
  // Internal Function(s):
  //
  
  static BOOL OnInit(HWND hwnd, HWND hwndFocus, LPARAM lParam)
  {
      // Set the limit
      //
      SendDlgItemMessage(hwnd, IDC_NAME_EDIT, EM_LIMITTEXT, MAX_CONFIG_NAME, 0);
  
      // Set the default config name.
      //
      SetWindowText(GetDlgItem(hwnd, IDC_NAME_EDIT), g_App.szConfigName);
  
      // Set the focus to the edit dialog
      //
      SetFocus(GetDlgItem(hwnd, IDC_NAME_EDIT));
  
      // Auto save if the auto run flag is set.
      //
      if ( GET_FLAG(OPK_AUTORUN) )
          PostMessage(GetDlgItem(hwnd, IDOK), BM_CLICK, 0, 0L);
  
      // Always return false to WM_INITDIALOG.
      //
      return FALSE;
  }
  
  static BOOL OnSave(HWND hwnd)
  {
      INT     nStrLen;
      TCHAR   szConfigDir[MAX_PATH],
              szLocalTempDir[MAX_PATH],
              szSharePath[MAX_PATH],
              szUsername[256],
              szPassword[256],
              szFullConfigName[MAX_PATH];
      LPTSTR  lpFullConfigName;
      LPTSTR  lpConfigName;
      BOOL    bSameConfig  = FALSE;
      DWORD   dwSize;
      HRESULT hrCat;
  
      // Check to see if they want to use an existing config set.
      //
  
      // Copy the configuration set directory name into the config directory buffer,
      // makeing sure there is a trailing backslash and that we have a pointer
      // to the end of the path.
      //
      lstrcpyn(szConfigDir, g_App.szConfigSetsDir,AS(szConfigDir));
      AddPathN(szConfigDir, NULLSTR,AS(szConfigDir));
      lpConfigName = szConfigDir + (nStrLen = lstrlen(szConfigDir));
  
      // Now grab the text from the control.
      //
      GetWindowText(GetDlgItem(hwnd, IDC_NAME_EDIT), lpConfigName, STRSIZE(szConfigDir) - nStrLen );
  
      // Validate the config name.
      //
      if ( *lpConfigName == NULLCHR )
      {
          MsgBox(hwnd, IDS_NOCONFIG, IDS_APPNAME, MB_ERRORBOX);
          SetFocus(GetDlgItem(hwnd, IDC_NAME_EDIT));
          return FALSE;
      }
  
      // get the full pathname, this will expand . or ..
      // if the entered name doesn't match the full name, we will consider this invalid and make user
      // either enter a valid filename or cancel
      dwSize=GetFullPathName(lpConfigName,AS(szFullConfigName),szFullConfigName,&lpFullConfigName);
      if (!dwSize || 
      	  (dwSize > AS(szFullConfigName)+1) ||
      	  lstrcmpi(lpFullConfigName, lpConfigName))
     {
          MsgBox(hwnd, IDS_CANNOTSAVE, IDS_APPNAME, MB_OK | MB_ICONERROR, lpConfigName);
          SetFocus(GetDlgItem(hwnd, IDC_NAME_EDIT));
          return FALSE;
      }
  
      // We need to make sure no ini files are cached and everything
      // is flushed to disk before we move the directory.
      //
      WritePrivateProfileString(NULL, NULL, NULL, g_App.szOpkWizIniFile);
  
  
      if (!lstrcmpi(g_App.szConfigName,lpConfigName))
          bSameConfig = TRUE;
     
      // Check to see if the directory exists.
      //
      if ( DirectoryExists(szConfigDir) )
      {
          // Check to see if we are updating an existing config or or ask the user
          // if they don't mind blowing away the existing directory.
          //
          if ( bSameConfig || MsgBox(hwnd, IDS_DIREXISTS, IDS_APPNAME, MB_YESNO | MB_ICONQUESTION, lpConfigName) == IDYES )
          {
              // Alright, remove the existing directory.
              //
              DeletePath(szConfigDir);
          }
          else
          {
              SetFocus(GetDlgItem(hwnd, IDC_NAME_EDIT));
              return FALSE;
          }
      }
  
      // Write out the config set name to the ini file
      //
      WritePrivateProfileString(INI_SEC_CONFIGSET, INI_SEC_CONFIG, lpConfigName, g_App.szOpkWizIniFile);
  
      // Need to also write the config set name to the winbom for WinPE.
      //
      WritePrivateProfileString(INI_SEC_WINPE, INI_KEY_WINPE_CFGSET, lpConfigName, g_App.szWinBomIniFile);
  
      // The password needs to have quotes around it.
      //
      lstrcpyn(szPassword, _T("\""),AS(szPassword));
  
      // Need to figure out what the share info is for the OPK stuff so we can write it out to
      // the winbom for WinPE.
      //
      if ( !GetShareSettings(szSharePath, AS(szSharePath), szUsername, AS(szUsername), szPassword + 1, AS(szPassword) - 1) )
      {
          if ( ( MsgBox(hwnd, IDS_ASK_SHARENOW, IDS_APPNAME, MB_OKCANCEL | MB_ICONWARNING | MB_APPLMODAL) == IDOK ) &&
               ( DistributionShareDialog(hwnd) ) )
          {
              GetShareSettings(szSharePath, AS(szSharePath), szUsername, AS(szUsername), szPassword + 1, AS(szPassword) - 1);
          }
          else
              MsgBox(hwnd, IDS_ERR_NOSHAREINFO, IDS_APPNAME, MB_ICONERROR);
      }
  
      // If there is a password, add the trailing quote.
      //
      if ( szPassword[1] )
          hrCat=StringCchCat(szPassword, AS(szPassword), _T("\""));
      else
          szPassword[0] = NULLCHR;
  
      // Now write out the settings.
      //
      // NTRAID#NTBUG9-531482-2002/02/27-stelo,swamip - Password stored in plain text
      WritePrivateProfileString(INI_SEC_WINPE, INI_KEY_WINPE_SRCROOT, szSharePath, g_App.szWinBomIniFile);
      WritePrivateProfileString(INI_SEC_WINPE, INI_KEY_WINPE_USERNAME, szUsername, g_App.szWinBomIniFile);
      WritePrivateProfileString(INI_SEC_WINPE, INI_KEY_WINPE_PASSWORD, szPassword, g_App.szWinBomIniFile);
  
      // If the user didn't specify custom credentials for the app preinstall stuff,
      // also write this stuff out to the factory section.
      //
      if ( GetPrivateProfileInt(INI_SEC_GENERAL, INI_KEY_APPCREDENTIALS, 0, g_App.szOpkWizIniFile) == 0 )
      {
          WritePrivateProfileString(WBOM_FACTORY_SECTION, INI_VAL_WBOM_USERNAME, szUsername, g_App.szWinBomIniFile);
          WritePrivateProfileString(WBOM_FACTORY_SECTION, INI_VAL_WBOM_PASSWORD, szPassword, g_App.szWinBomIniFile);
      }
  
      // Once we have the distribution share settings finished, we need
      // to make sure they have a runonce entry to install the SBSI stuff.
      //
      AddSbsiInstall(szSharePath);
  
      // Trim any backslashes off the directory names so we don't fail the MoveFile
      //
      lstrcpyn(szLocalTempDir, g_App.szTempDir,AS(szLocalTempDir));
      StrRTrm(szConfigDir, CHR_BACKSLASH);
      StrRTrm(szLocalTempDir, CHR_BACKSLASH);
  
      // Make sure the current directory is somewhere that won't cause us problems.
      // This is to fix WinXP bug 324896.
      //
      SetCurrentDirectory(g_App.szOpkDir);
  
      // Now try to move the temp directory to the new config directory.
      //
      if ( !MoveFile(szLocalTempDir, szConfigDir) )
      {
          // We already tried to remove the existing directory, so we must
          // be failing for some other reason.
          //
          #ifndef DBG
          MsgBox(hwnd, IDS_CANNOTSAVE, IDS_APPNAME, MB_OK | MB_ICONERROR, szConfigDir);
          #else // DBG
          DBGOUT(NULL, _T("OPKWIZ:  MoveFile('%s', '%s') failed.  GLE=%d\n"), szLocalTempDir, szConfigDir, GetLastError());
          DBGMSGBOX(hwnd, _T("Cannot save the config set.\n\nMoveFile('%s', '%s') failed.  GLE=%d"), _T("OPKWIZ Debug Message"), MB_ERRORBOX, szLocalTempDir, szConfigDir, GetLastError());
          #endif // DBG
          return FALSE;
      }
  
      // Now that we have saved the config set, update the global data with the right paths.
      //
      lstrcpyn(g_App.szTempDir, szConfigDir,AS(g_App.szTempDir));
      SetConfigPath(g_App.szTempDir);
      lstrcpyn(g_App.szConfigName, lpConfigName,AS(g_App.szConfigName));
  
      // The last thing to do before we return is to write the ini setting to say this config set is finished.
      //
      WritePrivateProfileString(INI_SEC_CONFIGSET, INI_KEY_FINISHED, STR_ONE, g_App.szOpkWizIniFile);
  
      // Now that it is saved, check if they want to make a winpe floppy.
      //
      if ( IsDlgButtonChecked(hwnd, IDC_SAVEAS_WINPEFLOPPY) == BST_CHECKED )
          MakeWinpeFloppy(hwnd, g_App.szConfigName, g_App.szWinBomIniFile);
  
      return TRUE;
  }
  
  static BOOL AddSbsiInstall(LPTSTR lpszShare)
  {
      BOOL        bRet            = FALSE,
                  bChanged        = FALSE;
      LPAPPENTRY  lpAppList,
                  lpAppSearch;
      APPENTRY    appSbsi;
      LPTSTR      lpszSbsiName    = AllocateString(NULL, IDS_INSTALLSBSI),
                  lpszSbsiPath;
      TCHAR       szLocalSbsiPath[MAX_PATH];
      HRESULT hrPrintf;
  
      // We have to have a friendly name to make this work.
      //
      if ( NULL == lpszSbsiName )
      {
          return FALSE;
      }
  
      // Start by clearing out the SBSI app structure.
      //
      ZeroMemory(&appSbsi, sizeof(APPENTRY));
  
      // Set the friendly name.
      //
      lstrcpyn(appSbsi.szDisplayName, lpszSbsiName, AS(appSbsi.szDisplayName));
      FREE(lpszSbsiName);
  
      // The source path starts with the distribution share.
      //
      lstrcpyn(appSbsi.szSourcePath, lpszShare, AS(appSbsi.szSourcePath));
  
      // Need to save this pointer, we will use this path to make sure the
      // SBSI content is there.
      //
      lpszSbsiPath = appSbsi.szSourcePath + lstrlen(appSbsi.szSourcePath);
  
      // Now create the rest of the path to where the content should be.
      //
      AddPathN(appSbsi.szSourcePath, g_App.szLangDir + lstrlen(g_App.szOpkDir), AS(appSbsi.szSourcePath));
      AddPathN(appSbsi.szSourcePath, g_App.szLangName, AS(appSbsi.szSourcePath));
      AddPathN(appSbsi.szSourcePath, DIR_SBSI, AS(appSbsi.szSourcePath));
      AddPathN(appSbsi.szSourcePath, g_App.szSkuName, AS(appSbsi.szSourcePath));
      AddPathN(appSbsi.szSourcePath, DIR_SBSI_SETUP, AS(appSbsi.szSourcePath));
  
      // This is the name of the setup program.
      //
      lstrcpyn(appSbsi.szSetupFile, FILE_SBSI_SETUP, AS(appSbsi.szSetupFile));
  
      // This will create the command line for the file.
      //
      hrPrintf=StringCchPrintf(appSbsi.szCommandLine, AS(appSbsi.szCommandLine), CMD_SBSI_SETUP, appSbsi.szSourcePath);
  
      // This is the base install tech type.
      //
  	appSbsi.itSectionType = installtechUndefined;
  
      // If there is a list, make sure our entry isn't already
      // there.
      //
      lpAppSearch = lpAppList = OpenAppList(g_App.szWinBomIniFile);
      while ( lpAppSearch && !bChanged)
      {
          if ( lstrcmp(lpAppSearch->szDisplayName, appSbsi.szDisplayName) == 0 )
          {
              if ( RemoveApp(&lpAppList, lpAppSearch) )
              {
                  bChanged = TRUE;
              }
          }
          else
          {
              lpAppSearch = lpAppSearch->lpNext;
          }
      }
  
      // Create the local path to the setup file where the SBSI content should
      // be.  Only if that exists to we add the app.
      //
      lstrcpyn(szLocalSbsiPath, g_App.szOpkDir, AS(szLocalSbsiPath));
      AddPathN(szLocalSbsiPath, lpszSbsiPath, AS(szLocalSbsiPath));
      AddPathN(szLocalSbsiPath, appSbsi.szSetupFile, AS(szLocalSbsiPath));
  
      // Now try to insert our SBSI stuff to the end of the list.
      //
      if ( FileExists(szLocalSbsiPath) &&
           InsertApp(&lpAppList, &appSbsi) )
      {
          bChanged = TRUE;
          bRet = TRUE;
      }
  
      // Save and close our list.
      //
      if ( lpAppList )
      {
          // Only need to save if we changed something.
          //
          if ( bChanged )
          {
              if ( !SaveAppList(lpAppList, g_App.szWinBomIniFile, g_App.szOpkWizIniFile) )
              {
                  bRet = FALSE;
              }
          }
  
          // This will free up the memory for the list.
          //
          CloseAppList(lpAppList);
      }
  
      return bRet;
  }
  