/*

MultiUser.nsh

Installer configuration for multi-user Windows environments

Copyright 2008-2018 Joost Verburg

*/

!ifndef MULTIUSER_INCLUDED
!define MULTIUSER_INCLUDED
!verbose push
!verbose 3

;Standard NSIS header files

!ifdef MULTIUSER_MUI
  !include MUI2.nsh
!endif
!include nsDialogs.nsh
!include LogicLib.nsh
!include WinVer.nsh
!include FileFunc.nsh

;Variables

Var MultiUser.Privileges
Var MultiUser.InstallMode

;Command line installation mode setting

!ifdef MULTIUSER_INSTALLMODE_COMMANDLINE
  !include StrFunc.nsh
  !ifndef StrStr_INCLUDED
    ${StrStr}
  !endif
  !ifndef MULTIUSER_NOUNINSTALL
    !ifndef UnStrStr_INCLUDED
      ${UnStrStr}
    !endif
  !endif
  
  Var MultiUser.Parameters
  Var MultiUser.Result
!endif

;Installation folder stored in registry

!ifdef MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_KEY & MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_VALUENAME
  Var MultiUser.InstDir
!endif

!ifdef MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_KEY & MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_VALUENAME
  Var MultiUser.DefaultKeyValue
!endif

;Windows Vista UAC setting

!if "${MULTIUSER_EXECUTIONLEVEL}" == Admin
  RequestExecutionLevel admin
  !define MULTIUSER_EXECUTIONLEVEL_ALLUSERS
!else if "${MULTIUSER_EXECUTIONLEVEL}" == Power
  RequestExecutionLevel admin
  !define MULTIUSER_EXECUTIONLEVEL_ALLUSERS
!else if "${MULTIUSER_EXECUTIONLEVEL}" == Highest
  RequestExecutionLevel highest
  !define MULTIUSER_EXECUTIONLEVEL_ALLUSERS
!else
  RequestExecutionLevel user
!endif

/*

Install modes

*/

!macro MULTIUSER_INSTALLMODE_ALLUSERS UNINSTALLER_PREFIX UNINSTALLER_FUNCPREFIX

  ;Install mode initialization - per-machine

  ${ifnot} ${IsNT}
    ${orif} $MultiUser.Privileges == "Admin"
    ${orif} $MultiUser.Privileges == "Power"
  
    StrCpy $MultiUser.InstallMode AllUsers
  
    SetShellVarContext all
  
    !if "${UNINSTALLER_PREFIX}" != UN
      ;Set default installation location for installer
      !ifdef MULTIUSER_INSTALLMODE_INSTDIR
        !ifdef MULTIUSER_USE_PROGRAMFILES64
          StrCpy $INSTDIR "$PROGRAMFILES64\${MULTIUSER_INSTALLMODE_INSTDIR}"
        !else
          StrCpy $INSTDIR "$PROGRAMFILES\${MULTIUSER_INSTALLMODE_INSTDIR}"
        !endif
      !endif
    !endif
  
    !ifdef MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_KEY & MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_VALUENAME
  
      ReadRegStr $MultiUser.InstDir HKLM "${MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_KEY}" "${MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_VALUENAME}"
  
      ${if} $MultiUser.InstDir != ""
        StrCpy $INSTDIR $MultiUser.InstDir
      ${endif}
  
    !endif
  
    !ifdef MULTIUSER_INSTALLMODE_${UNINSTALLER_PREFIX}FUNCTION
      Call "${MULTIUSER_INSTALLMODE_${UNINSTALLER_PREFIX}FUNCTION}"
    !endif
    
  ${endif}

!macroend

!macro MULTIUSER_INSTALLMODE_CURRENTUSER UNINSTALLER_PREFIX UNINSTALLER_FUNCPREFIX

  ;Install mode initialization - per-user
  
  ${if} ${IsNT}  
  
    StrCpy $MultiUser.InstallMode CurrentUser
    
    SetShellVarContext current
  
    !if "${UNINSTALLER_PREFIX}" != UN
      ;Set default installation location for installer  
      !ifdef MULTIUSER_INSTALLMODE_INSTDIR
        ${if} ${AtLeastWin2000}
          StrCpy $INSTDIR "$LOCALAPPDATA\${MULTIUSER_INSTALLMODE_INSTDIR}"
        ${else}
          StrCpy $INSTDIR "$PROGRAMFILES\${MULTIUSER_INSTALLMODE_INSTDIR}"
        ${endif}
      !endif
    !endif
  
    !ifdef MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_KEY & MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_VALUENAME
  
      ReadRegStr $MultiUser.InstDir HKCU "${MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_KEY}" "${MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_VALUENAME}"
  
      ${if} $MultiUser.InstDir != ""
        StrCpy $INSTDIR $MultiUser.InstDir
      ${endif}
  
    !endif
  
    !ifdef MULTIUSER_INSTALLMODE_${UNINSTALLER_PREFIX}FUNCTION
      Call "${MULTIUSER_INSTALLMODE_${UNINSTALLER_PREFIX}FUNCTION}"
    !endif
  
  ${endif}

!macroend

Function MultiUser.InstallMode.AllUsers
  !insertmacro MULTIUSER_INSTALLMODE_ALLUSERS "" ""
FunctionEnd

Function MultiUser.InstallMode.CurrentUser
  !insertmacro MULTIUSER_INSTALLMODE_CURRENTUSER "" ""
FunctionEnd

!ifndef MULTIUSER_NOUNINSTALL

Function un.MultiUser.InstallMode.AllUsers
  !insertmacro MULTIUSER_INSTALLMODE_ALLUSERS UN .un
FunctionEnd

Function un.MultiUser.InstallMode.CurrentUser
  !insertmacro MULTIUSER_INSTALLMODE_CURRENTUSER UN .un
FunctionEnd

!endif

/*

Installer/uninstaller initialization

*/

!macro MULTIUSER_INIT_QUIT UNINSTALLER_FUNCPREFIX

  !ifdef MULTIUSER_INIT_${UNINSTALLER_FUNCPREFIX}FUNCTIONQUIT
    Call "${MULTIUSER_INIT_${UNINSTALLER_FUNCPREFIX}FUCTIONQUIT}
  !else
    Quit
  !endif

!macroend

!macro MULTIUSER_INIT_TEXTS

  !ifndef MULTIUSER_INIT_TEXT_ADMINREQUIRED
    !define MULTIUSER_INIT_TEXT_ADMINREQUIRED "$(^Caption) requires administrator privileges."
  !endif

  !ifndef MULTIUSER_INIT_TEXT_POWERREQUIRED
    !define MULTIUSER_INIT_TEXT_POWERREQUIRED "$(^Caption) requires at least Power User privileges."
  !endif

  !ifndef MULTIUSER_INIT_TEXT_ALLUSERSNOTPOSSIBLE
    !define MULTIUSER_INIT_TEXT_ALLUSERSNOTPOSSIBLE "Your user account does not have sufficient privileges to install $(^Name) for all users of this computer."
  !endif

!macroend

!macro MULTIUSER_INIT_CHECKS UNINSTALLER_PREFIX UNINSTALLER_FUNCPREFIX

  ;Installer initialization - check privileges and set install mode

  !insertmacro MULTIUSER_INIT_TEXTS

  UserInfo::GetAccountType
  Pop $MultiUser.Privileges
  
  ${if} ${IsNT}
  
    ;Check privileges
  
    !if "${MULTIUSER_EXECUTIONLEVEL}" == Admin
  
      ${if} $MultiUser.Privileges != "Admin"
        MessageBox MB_OK|MB_ICONSTOP "${MULTIUSER_INIT_TEXT_ADMINREQUIRED}"
        !insertmacro MULTIUSER_INIT_QUIT "${UNINSTALLER_FUNCPREFIX}"
      ${endif}
  
    !else if "${MULTIUSER_EXECUTIONLEVEL}" == Power
  
      ${if} $MultiUser.Privileges != "Power"
        ${andif} $MultiUser.Privileges != "Admin"
        ${if} ${AtMostWinXP}
           MessageBox MB_OK|MB_ICONSTOP "${MULTIUSER_INIT_TEXT_POWERREQUIRED}"
        ${else}
           MessageBox MB_OK|MB_ICONSTOP "${MULTIUSER_INIT_TEXT_ADMINREQUIRED}"
        ${endif}        
        !insertmacro MULTIUSER_INIT_QUIT "${UNINSTALLER_FUNCPREFIX}"
      ${endif}
  
    !endif
    
    !ifdef MULTIUSER_EXECUTIONLEVEL_ALLUSERS
    
      ;Default to per-machine installation if possible
    
      ${if} $MultiUser.Privileges == "Admin"
        ${orif} $MultiUser.Privileges == "Power"
        !ifndef MULTIUSER_INSTALLMODE_DEFAULT_CURRENTUSER
          Call ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallMode.AllUsers
        !else
          Call ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallMode.CurrentUser
        !endif

        !ifdef MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_KEY & MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_VALUENAME

          ;Set installation mode to setting from a previous installation

          !ifndef MULTIUSER_INSTALLMODE_DEFAULT_CURRENTUSER
            ReadRegStr $MultiUser.DefaultKeyValue HKLM "${MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_KEY}" "${MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_VALUENAME}"
            ${if} $MultiUser.DefaultKeyValue == ""
              ReadRegStr $MultiUser.DefaultKeyValue HKCU "${MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_KEY}" "${MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_VALUENAME}"
              ${if} $MultiUser.DefaultKeyValue != ""
                Call ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallMode.CurrentUser
              ${endif}
            ${endif}
          !else
            ReadRegStr $MultiUser.DefaultKeyValue HKCU "${MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_KEY}" "${MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_VALUENAME}"
            ${if} $MultiUser.DefaultKeyValue == ""
              ReadRegStr $MultiUser.DefaultKeyValue HKLM "${MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_KEY}" "${MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_VALUENAME}"
              ${if} $MultiUser.DefaultKeyValue != ""
                Call ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallMode.AllUsers
              ${endif}
            ${endif}
          !endif

        !endif

      ${else}
        Call ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallMode.CurrentUser
      ${endif}
    
    !else

      Call ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallMode.CurrentUser

    !endif  
  
    !ifdef MULTIUSER_INSTALLMODE_COMMANDLINE
    
      ;Check for install mode setting on command line

      ${${UNINSTALLER_FUNCPREFIX}GetParameters} $MultiUser.Parameters
  
      ${${UNINSTALLER_PREFIX}StrStr} $MultiUser.Result $MultiUser.Parameters "/CurrentUser"    
    
      ${if} $MultiUser.Result != ""
        Call ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallMode.CurrentUser
      ${endif}    
  
      ${${UNINSTALLER_PREFIX}StrStr} $MultiUser.Result $MultiUser.Parameters "/AllUsers"    
    
      ${if} $MultiUser.Result != ""
        ${if} $MultiUser.Privileges == "Admin"
          ${orif} $MultiUser.Privileges == "Power"
          Call ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallMode.AllUsers
        ${else}
          MessageBox MB_OK|MB_ICONSTOP "${MULTIUSER_INIT_TEXT_ALLUSERSNOTPOSSIBLE}"
        ${endif}
      ${endif}
  
    !endif
    
  ${else}
  
    ;Not running Windows NT, per-user installation not supported
    
    Call ${UNINSTALLER_FUNCPREFIX}MultiUser.InstallMode.AllUsers
  
  ${endif}

!macroend

!macro MULTIUSER_INIT
  !verbose push
  !verbose 3
  
  !insertmacro MULTIUSER_INIT_CHECKS "" ""
  
  !verbose pop 
!macroend

!ifndef MULTIUSER_NOUNINSTALL

!macro MULTIUSER_UNINIT
  !verbose push
  !verbose 3
  
  !insertmacro MULTIUSER_INIT_CHECKS Un un.
  
  !verbose pop 
!macroend

!endif

/*

Modern UI 2 page

*/

!ifdef MULTIUSER_MUI

!macro MULTIUSER_INSTALLMODEPAGE_INTERFACE

  !ifndef MULTIUSER_INSTALLMODEPAGE_INTERFACE
    !define MULTIUSER_INSTALLMODEPAGE_INTERFACE
    Var MultiUser.InstallModePage
    
    Var MultiUser.InstallModePage.Text
    
    Var MultiUser.InstallModePage.AllUsers
    Var MultiUser.InstallModePage.CurrentUser
    
    Var MultiUser.InstallModePage.ReturnValue
  !endif

!macroend

!macro MULTIUSER_PAGEDECLARATION_INSTALLMODE

  !insertmacro MUI_SET MULTIUSER_${MUI_PAGE_UNINSTALLER_PREFIX}INSTALLMODEPAGE ""
  !insertmacro MULTIUSER_INSTALLMODEPAGE_INTERFACE

  !insertmacro MUI_DEFAULT MULTIUSER_INSTALLMODEPAGE_TEXT_TOP "$(MULTIUSER_INNERTEXT_INSTALLMODE_TOP)"
  !insertmacro MUI_DEFAULT MULTIUSER_INSTALLMODEPAGE_TEXT_ALLUSERS "$(MULTIUSER_INNERTEXT_INSTALLMODE_ALLUSERS)"
  !insertmacro MUI_DEFAULT MULTIUSER_INSTALLMODEPAGE_TEXT_CURRENTUSER "$(MULTIUSER_INNERTEXT_INSTALLMODE_CURRENTUSER)"  

  PageEx custom

    PageCallbacks MultiUser.InstallModePre_${MUI_UNIQUEID} MultiUser.InstallModeLeave_${MUI_UNIQUEID}

    Caption " "

  PageExEnd

  !insertmacro MULTIUSER_FUNCTION_INSTALLMODEPAGE MultiUser.InstallModePre_${MUI_UNIQUEID} MultiUser.InstallModeLeave_${MUI_UNIQUEID}

  !undef MULTIUSER_INSTALLMODEPAGE_TEXT_TOP
  !undef MULTIUSER_INSTALLMODEPAGE_TEXT_ALLUSERS
  !undef MULTIUSER_INSTALLMODEPAGE_TEXT_CURRENTUSER

!macroend

!macro MULTIUSER_PAGE_INSTALLMODE

  ;Modern UI page for install mode

  !verbose push
  !verbose 3
  
  !ifndef MULTIUSER_EXECUTIONLEVEL_ALLUSERS
    !error "A mixed-mode installation requires MULTIUSER_EXECUTIONLEVEL to be set to Admin, Power or Highest."
  !endif
  
  !insertmacro MUI_PAGE_INIT
  !insertmacro MULTIUSER_PAGEDECLARATION_INSTALLMODE
  
  !verbose pop

!macroend

!macro MULTIUSER_FUNCTION_INSTALLMODEPAGE PRE LEAVE

  ;Page functions of Modern UI page

  Function "${PRE}"
  
    ${ifnot} ${IsNT}
      Abort
    ${endif}
  
    ${if} $MultiUser.Privileges != "Power"
      ${andif} $MultiUser.Privileges != "Admin"
      Abort
    ${endif}
    
    !insertmacro MUI_PAGE_FUNCTION_CUSTOM PRE
    !insertmacro MUI_HEADER_TEXT_PAGE $(MULTIUSER_TEXT_INSTALLMODE_TITLE) $(MULTIUSER_TEXT_INSTALLMODE_SUBTITLE)
    
    nsDialogs::Create 1018
    Pop $MultiUser.InstallModePage

    ${NSD_CreateLabel} 0u 0u 300u 40u "${MULTIUSER_INSTALLMODEPAGE_TEXT_TOP}"
    Pop $MultiUser.InstallModePage.Text

    ${NSD_CreateRadioButton} 20u 50u 280u 10u "${MULTIUSER_INSTALLMODEPAGE_TEXT_ALLUSERS}"
    Pop $MultiUser.InstallModePage.AllUsers
    
    ${NSD_CreateRadioButton} 20u 70u 280u 10u "${MULTIUSER_INSTALLMODEPAGE_TEXT_CURRENTUSER}"
    Pop $MultiUser.InstallModePage.CurrentUser
    
    ${if} $MultiUser.InstallMode == "AllUsers"
      SendMessage $MultiUser.InstallModePage.AllUsers ${BM_SETCHECK} ${BST_CHECKED} 0
    ${else}
      SendMessage $MultiUser.InstallModePage.CurrentUser ${BM_SETCHECK} ${BST_CHECKED} 0
    ${endif}
    
    !insertmacro MUI_PAGE_FUNCTION_CUSTOM SHOW
    nsDialogs::Show
    !insertmacro MUI_PAGE_FUNCTION_CUSTOM DESTROYED
    
  FunctionEnd

  Function "${LEAVE}"
     SendMessage $MultiUser.InstallModePage.AllUsers ${BM_GETCHECK} 0 0 $MultiUser.InstallModePage.ReturnValue
     
     ${if} $MultiUser.InstallModePage.ReturnValue = ${BST_CHECKED}
        Call MultiUser.InstallMode.AllUsers
     ${else}
        Call MultiUser.InstallMode.CurrentUser
     ${endif}
  
    !insertmacro MUI_PAGE_FUNCTION_CUSTOM LEAVE
  FunctionEnd

!macroend

!endif

!verbose pop
!endif
