//*********************************************************************
//*                  Microsoft Windows                               **
//*            Copyright (c) 1994-1999 Microsoft Corporation
//*********************************************************************

//
//  CFGAPI.C - Functions for exported config API.
//

//  HISTORY:
//  
//  96/05/22  markdu  Created (from inetcfg.dll)
//  96/05/25  markdu  Use ICFG_ flags for lpNeedDrivers and lpInstallDrivers.
//  96/05/27  markdu  Added lpGetLastInstallErrorText.
//

#include "pch.hpp"

UINT DetectModifyTCPIPBindings(DWORD dwCardFlags,LPCSTR pszBoundTo,BOOL fRemove,BOOL * pfBound);


//*******************************************************************
//
//  FUNCTION:   IcfgGetLastInstallErrorText
//
//  PURPOSE:    Get a text string that describes the last installation
//              error that occurred.  The string should be suitable
//              for display in a message box with no further formatting.
//
//  PARAMETERS: lpszErrorDesc - points to buffer to receive the string.
//              cbErrorDesc - size of buffer.
//
//  RETURNS:    The length of the string returned.
//
//*******************************************************************

extern "C" DWORD IcfgGetLastInstallErrorText(LPSTR lpszErrorDesc, DWORD cbErrorDesc)
{
  if (lpszErrorDesc)
  {
    lstrcpyn(lpszErrorDesc, gpszLastErrorText, cbErrorDesc);
    return lstrlen(lpszErrorDesc);
  }
  else
  {
    return 0;
  }
}


//*******************************************************************
//
//  FUNCTION:   IcfgNeedInetComponents
//
//  PURPOSE:    Detects whether the specified system components are
//              installed or not.
//
//  PARAMETERS: dwfOptions - a combination of ICFG_ flags that specify
//              which components to detect as follows:
//
//                ICFG_INSTALLTCP - is TCP/IP needed?
//                ICFG_INSTALLRAS - is RAS needed?
//                ICFG_INSTALLMAIL - is exchange or internet mail needed?
//
//              lpfNeedComponents - TRUE if any specified component needs
//              to be installed.
//
//  RETURNS:    HRESULT code, ERROR_SUCCESS if no errors occurred
//
//  History:	5/8/97 ChrisK Added INSTALLLAN,INSTALLDIALUP,INSTALLTCPONLY
//
//*******************************************************************

extern "C" HRESULT IcfgNeedInetComponents(DWORD dwfOptions, LPBOOL lpfNeedComponents)
{
  CLIENTCONFIG  ClientConfig;

  DEBUGMSG("cfgapi.c::IcfgNeedInetComponents()");

  ASSERT(lpfNeedComponents);

  // read client configuration
  ZeroMemory(&ClientConfig,sizeof(CLIENTCONFIG));
  DWORD dwErrCls;
  UINT err=GetConfig(&ClientConfig,&dwErrCls);
  if (err != OK)
  {
    PrepareErrorMessage(IDS_ERRReadConfig,(UINT) err,
      dwErrCls,MB_ICONEXCLAMATION);
    return err;
  }

  // check if we are allowed to install TCP/IP
  if (dwfOptions & ICFG_INSTALLTCP)
  {
    // need TCP/IP present and bound to PPP driver
    if (!ClientConfig.fPPPBoundTCP)
    {
      if (lpfNeedComponents)
      {
        *lpfNeedComponents = TRUE;
      }
      return ERROR_SUCCESS;
    }
  }

  // check if we are allowed to install RNA
  if (dwfOptions & ICFG_INSTALLRAS)
  {
    // need PPPMAC and RNA files if using modem
    if (!ClientConfig.fRNAInstalled ||
      !ClientConfig.fPPPDriver)
    {
      if (lpfNeedComponents)
      {
        *lpfNeedComponents = TRUE;
      }
      return ERROR_SUCCESS;
    }
  }

  // need Exchange if not installed and user wants to install mail
  if ((dwfOptions & ICFG_INSTALLMAIL) &&
    (!ClientConfig.fMailInstalled || !ClientConfig.fInetMailInstalled))
  {
    if (lpfNeedComponents)
    {
      *lpfNeedComponents = TRUE;
    }
    return ERROR_SUCCESS;
  }

  //
  // ChrisK	5/8/97
  // check if we have a bound LAN adapter
  //
  if (dwfOptions & ICFG_INSTALLLAN)
  {
	  if (!ClientConfig.fNetcard ||
		  !ClientConfig.fNetcardBoundTCP)
	  {
		  if (lpfNeedComponents)
		  {
			  *lpfNeedComponents = TRUE;
		  }
		  return ERROR_SUCCESS;
	  }
  }

  //
  // ChrisK	5/8/97
  // Check if we have a bound Dial up adapter
  //
  if (dwfOptions & ICFG_INSTALLDIALUP)
  {
	  if (!ClientConfig.fPPPDriver ||
		  !ClientConfig.fPPPBoundTCP)
	  {
		  if (lpfNeedComponents)
		  {
			  *lpfNeedComponents = TRUE;
		  }
		  return ERROR_SUCCESS;
	  }
  }

  //
  // ChrisK	5/8/97
  // Check if TCP is install at all on this system
  //
  if (dwfOptions & ICFG_INSTALLTCPONLY)
  {
	  if (!ClientConfig.fTcpip)
	  {
		  if (lpfNeedComponents)
		  {
			  *lpfNeedComponents = TRUE;
		  }
		  return ERROR_SUCCESS;
	  }
  }

  // no extra drivers needed
  if (lpfNeedComponents)
  {
    *lpfNeedComponents = FALSE;
  }
  return ERROR_SUCCESS;
}


//*******************************************************************
//
//  FUNCTION:   IcfgInstallInetComponents
//
//  PURPOSE:    Install the specified system components.
//
//  PARAMETERS: hwndParent - Parent window handle.
//              dwfOptions - a combination of ICFG_ flags that controls
//              the installation and configuration as follows:
//
//                ICFG_INSTALLTCP - install TCP/IP (if needed)
//                ICFG_INSTALLRAS - install RAS (if needed)
//                ICFG_INSTALLMAIL - install exchange and internet mail
//              
//              lpfNeedsRestart - if non-NULL, then on return, this will be
//              TRUE if windows must be restarted to complete the installation.
//
//  RETURNS:    HRESULT code, ERROR_SUCCESS if no errors occurred
//
//*******************************************************************

extern "C" HRESULT IcfgInstallInetComponents(HWND hwndParent, DWORD dwfOptions,
  LPBOOL lpfNeedsRestart)
{
  RETERR err;
  DWORD dwFiles = 0;
  BOOL  fInitNetMAC = FALSE;
  BOOL  fNeedTCPIP=FALSE;
  BOOL  fNeedPPPMAC=FALSE;
  BOOL  fNeedToRemoveTCPIP=FALSE;
  BOOL  fNeedReboot = FALSE;
  DWORD dwErrCls;
  CLIENTCONFIG  ClientConfig;

  DEBUGMSG("cfgapi.c::IcfgInstallInetComponents()");

  // read client configuration
  ZeroMemory(&ClientConfig,sizeof(CLIENTCONFIG));
  err=GetConfig(&ClientConfig,&dwErrCls);
  if (err != OK)
  {
    PrepareErrorMessage(IDS_ERRReadConfig,(UINT) err,
      dwErrCls,MB_ICONEXCLAMATION);
    return err;
  }

  // see if we initially have any kind of net card
  fInitNetMAC = (ClientConfig.fNetcard | ClientConfig.fPPPDriver);

  // install files we need

  // install mail if user wants it and not already installed
  if (dwfOptions & ICFG_INSTALLMAIL)
  {
    // need mail files (capone)? 
    if (!ClientConfig.fMailInstalled)
    {
      DEBUGMSG("Installing Exchange files");
      dwFiles |= ICIF_MAIL;
    }

    // need internet mail files (rt 66)?
    if (!ClientConfig.fInetMailInstalled)
    {
      DEBUGMSG("Installing Internet Mail files");
      dwFiles |= ICIF_INET_MAIL;
    }
  }

  // check if we are allowed to install RNA
  if (dwfOptions & ICFG_INSTALLRAS)
  {
    // install RNA if user is connecting over modem and RNA
    // not already installed
    if (!ClientConfig.fRNAInstalled)
    {
      DEBUGMSG("Installing RNA files");
      dwFiles |= ICIF_RNA;
    }
  }

  if (dwFiles)
  {
    {
      WAITCURSOR WaitCursor;  // show hourglass
      // install the component files
      err = InstallComponent(hwndParent,IC_INSTALLFILES,
        dwFiles);
      if (err == NEED_RESTART)
      {
        DEBUGMSG("Setting restart flag");
        // set restart flag so we restart the system at end
        fNeedReboot = TRUE;
        // NEED_REBOOT also implies success, so set ret code to OK
        err = OK;
      }

      // force an update of the dialog
      if (hwndParent)
      {
        HWND hParent = GetParent(hwndParent);
        UpdateWindow(hParent ? hParent : hwndParent);
      }

      // runonce.exe may get run at next boot, twiddle the
      // registry to work around a bug where it trashes the wallpaper
      PrepareForRunOnceApp();
    }

    if (err != OK)
    {
      PrepareErrorMessage(IDS_ERRInstallFiles,(UINT) err,
        ERRCLS_SETUPX,MB_ICONEXCLAMATION);
      return err;
    }

    WAITCURSOR WaitCursor;  // show hourglass

    // do some extra stuff if we just installed mail
    if (dwFiles & ICIF_MAIL)
    {
      // .inf file leaves an entry in the registry to run
      // MS Exchange wizard, which we don't need since we'll be
      // configuring exchange ourselves.  Remove the registry
      // entry.
      RemoveRunOnceEntry(IDS_MAIL_WIZARD_REG_VAL);

      // run mlset32, Exchange setup app that it needs to have run.
      // need to display error if this fails, this is fairly important.
      err=RunMlsetExe(hwndParent);
      if (err != ERROR_SUCCESS)
      {
        PrepareErrorMessage(IDS_ERRInstallFiles,(UINT) err,
          ERRCLS_STANDARD,MB_ICONEXCLAMATION);
        return err;
      }
    }

    // run the group converter to put the Inbox icon on desktop,
    // put Exchange, RNA et al on start menu
    CHAR szExecGrpconv[SMALL_BUF_LEN],szParam[SMALL_BUF_LEN];
    LoadSz(IDS_EXEC_GRPCONV,szExecGrpconv,sizeof(szExecGrpconv));
    LoadSz(IDS_EXEC_GRPCONV_PARAM,szParam,sizeof(szParam));
    ShellExecute(NULL,NULL,szExecGrpconv,szParam,NULL,SW_SHOW);

  }

  // only install PPPMAC if we are allowed to install RNA
  if (dwfOptions & ICFG_INSTALLRAS)
  {
    // install PPPMAC if not already installed
    // Note that we have to install PPPMAC *before* TCP/IP, to work
    // in the case where the user has no net installed to start with.
    // Otherwise when we install TCP/IP, user gets prompted by net setup
    // for their net card; net setup doesn't like the idea of TCP/IP lying
    // around without something to bind it to.
    fNeedPPPMAC = (!ClientConfig.fPPPDriver);
    if (fNeedPPPMAC)
    {
      DEBUGMSG("Installing PPPMAC");

      // make up a computer and workgroup name if not already set, so
      // user doesn't get prompted
      GenerateComputerNameIfNeeded();
      
      err = InstallPPPMAC(hwndParent);

      //  96/05/20  markdu  MSN  BUG 8551 Check for reboot when installing PPPMAC.

	  //
	  // ChrisK 5/29/97 Olympus 4692
	  // Even if we just rebind PPPMAC we still need to restart the machine.
	  //
      if (err == NEED_RESTART || err == OK)
      {
        // set restart flag so we restart the system at end
        DEBUGMSG("Setting restart flag");
        fNeedReboot = TRUE;

        // NEED_REBOOT also implies success, so set ret code to OK
        err = OK;
      }

      if (err != OK)
      {
        PrepareErrorMessage(IDS_ERRInstallPPPMAC,(UINT) err,
          ERRCLS_SETUPX,MB_ICONEXCLAMATION);
        return err;
      }

      // when we install PPPMAC, if there is another net card then PPPMAC
      // will automatically "grow" all the protocols that were bound to the
      // net card.  Strip these off... (netbeui and IPX)
      RETERR errTmp = RemoveProtocols(hwndParent,INSTANCE_PPPDRIVER,
        PROT_NETBEUI | PROT_IPX);
      ASSERT(errTmp == OK);
    }
  }

  // check if we are allowed to install TCP/IP
  if (dwfOptions & ICFG_INSTALLTCP)
  {
    // figure out if we need to install TCP/IP
    // we should only put TCP/IP on appropriate type of card (net card
    // or PPP adapter)
    // user is connecting via modem, need TCP if not already present
    // and bound to PPPMAC.  Want to bind to PPP adapters, 

    //
    // As of W98, PPPMAC install also binds TCP/IP to dial-up adapter. Re-read 
    // the config using a temporary instance of the structure to determine if
    // we still need the binding. 
    // nickball - 03/03/99 - Olympus #49008, Memphis #88375, NT #180684.
    //

    CLIENTCONFIG  TmpConfig;
    ZeroMemory(&TmpConfig,sizeof(CLIENTCONFIG));

	err=GetConfig(&TmpConfig,&dwErrCls);

    if (err != OK)
    {
      PrepareErrorMessage(IDS_ERRReadConfig,(UINT) err,
        dwErrCls,MB_ICONEXCLAMATION);
      return err;
    }

    fNeedTCPIP = !TmpConfig.fPPPBoundTCP;
    
    if (fNeedTCPIP && ClientConfig.fNetcard &&
      !ClientConfig.fNetcardBoundTCP)
    {
      // if we have to add TCP to PPP driver, then check if TCP is already
      // on netcard.  If not, then TCP is going to glom on to netcard as
      // well as PPP driver when we install it, need to remove it from
      // netcard later.
      fNeedToRemoveTCPIP= TRUE;
    }

    // special case: if there were any existing instances of TCP/IP and
    // we just added PPPMAC then we don't need to install TCP/IP --
    // when the PPPMAC adapter got added it automatically gets an instance
    // of all installed protocols (incl. TCP/IP) created for it
    if (ClientConfig.fTcpip && fNeedPPPMAC)
    {
      fNeedTCPIP = FALSE;
    }
  } // if (dwfOptions & ICFG_INSTALLTCP)

  // install TCP/IP if necessary
  if (fNeedTCPIP)
  {
    DEBUGMSG("Installing TCP/IP");
    // call out to device manager to install TCP/IP
    err = InstallTCPIP(hwndParent);      

    //  96/05/20  markdu  MSN  BUG 8551 Check for reboot when installing TCP/IP.
    if (err == NEED_RESTART)
    {
      // NEED_REBOOT also implies success, so set ret code to OK
      // Reboot flag is set below ALWAYS.  Should really be set here,
      // but we don't want to suddenly stop rebooting in cases
      // where we used to reboot, even if not needed.
      err = OK;
    }

     if (err != OK)
     {
      PrepareErrorMessage(IDS_ERRInstallTCPIP,(UINT) err,
        ERRCLS_SETUPX,MB_ICONEXCLAMATION);
      return err;
    }

    if (fNeedToRemoveTCPIP)
    {
      // remove TCPIP that may have glommed onto net drivers other
      // than the one we intend it for
      UINT uErrTmp;
      uErrTmp=RemoveProtocols(hwndParent,INSTANCE_NETDRIVER,PROT_TCPIP);
      ASSERT(uErrTmp == OK);
    }

    DEBUGMSG("Setting restart flag");
    // set restart flag so we restart the system at end
    fNeedReboot = TRUE;
  }

  // if we just installed TCP/IP or PPPMAC, then adjust bindings 
  if (fNeedPPPMAC || fNeedTCPIP)
  {
    UINT uErrTmp;

    // if file sharing (vserver) is installed, TCP/IP will bind
    // to it by default.  This is bad, user could be sharing
    // files to Internet without knowing it.  Unbind VSERVER
    // from TCP/IP instances that may used to connect to Internet
    // (instances of type INSTANCE_PPPDRIVER)
    uErrTmp = IcfgTurnOffFileSharing(INSTANCE_PPPDRIVER, hwndParent);
    ASSERT (uErrTmp == ERROR_SUCCESS);

    // unbind TCP/IP from VREDIR, if bound on this card type
    BOOL fBound;
    uErrTmp = DetectModifyTCPIPBindings(INSTANCE_PPPDRIVER,szVREDIR,
      TRUE,&fBound);
    ASSERT(uErrTmp == ERROR_SUCCESS);
  }

  // refresh the client configuration info
  err = GetConfig(&ClientConfig,&dwErrCls);
  if (err != OK)
  {
    PrepareErrorMessage(IDS_ERRReadConfig,(UINT) err,
      dwErrCls,MB_ICONEXCLAMATION);
    return err;
  }

  // do some special handling if there were *no* netcard devices
  // (net cards or PPP drivers) initially installed
  if (!fInitNetMAC)
  {
    ASSERT(fNeedPPPMAC);  // should have just installed PPPMAC

    // net setup adds some extra net components "by default" when
    // we add PPPMAC and there are no net card devices, go kill them
    // off.
    RETERR reterr = RemoveUnneededDefaultComponents(hwndParent);
    ASSERT(reterr == OK);

    // since there were no net card devices to begin with, we need
    // to restart the system later.  (the NDIS VxD is a static VxD
    // which needs to run, only gets added when you install a net card.)

    DEBUGMSG("Setting restart flag");
    // set restart flag so we restart the system at end
    fNeedReboot = TRUE;
  }

  // tell caller whether we need to reboot or not
  if (lpfNeedsRestart)
  {
    *lpfNeedsRestart = fNeedReboot;
  }
  return ERROR_SUCCESS;
}


/*******************************************************************

  NAME:    GetConfig

  SYNOPSIS:  Retrieves client configuration

********************************************************************/
UINT GetConfig(CLIENTCONFIG * pClientConfig,DWORD * pdwErrCls)
{
  ASSERT(pClientConfig);
  ASSERT(pdwErrCls);

  // get most the client configuration from 16-bit dll
  UINT uRet = GetClientConfig(pClientConfig);
  if (uRet != OK) {
    // GetClientConfig returns SETUPX error codes
    *pdwErrCls = ERRCLS_SETUPX;
  } 

  return uRet;
}

//*******************************************************************
//
//  FUNCTION:   IcfgStartServices
//
//  PURPOSE:    This is a NOP designed to maintain parity with the NT
//              version (icfgnt.dll).
//
//  PARAMETERS: none
//
//  RETURNS:    HRESULT code, ERROR_SUCCESS if no errors occurred
//
//*******************************************************************

extern "C" HRESULT IcfgStartServices()
{
	return ERROR_SUCCESS;
}

