!addplugindir /x86-unicode x86-unicode

SetPluginUnload alwaysoff

!if ${SIGN} == 1
	!finalize       '../build/sign.sh "%1"'
	!uninstfinalize '../build/sign.sh "%1"'
!endif

!define IsNativeIA64 '${IsNativeMachineArchitecture} ${IMAGE_FILE_MACHINE_IA64}'

Function GetArch
	Var /GLOBAL Arch
	${If} $Arch == ""
		${If} ${IsNativeIA32}
			StrCpy $Arch "x86"
		${ElseIf} ${IsNativeAMD64}
			StrCpy $Arch "x64"
		${ElseIf} ${IsNativeIA64}
			StrCpy $Arch "ia64"
		${Else}
			StrCpy $Arch ""
		${EndIf}
	${EndIf}
	Push $Arch
FunctionEnd

!macro _HasFlag _a _b _t _f
	!insertmacro _LOGICLIB_TEMP
	${GetParameters} $_LOGICLIB_TEMP
	ClearErrors
	${GetOptions} $_LOGICLIB_TEMP `${_b}` $_LOGICLIB_TEMP
	IfErrors `${_f}` `${_t}`
!macroend

!define IsActiveXInstall `"" HasFlag "/activex"`
!define IsHelp           `"" HasFlag "/?"`

!macro DetailPrint text
	SetDetailsPrint both
	DetailPrint "${text}"
	SetDetailsPrint listonly
!macroend

Var /GLOBAL Download.ID

!macro DownloadRequest url local extra
	NSxfer::Request \
		/TIMEOUTCONNECT 60000 \
		/TIMEOUTRECONNECT 60000 \
		/OPTCONNECTTIMEOUT 60000 \
		/OPTRECEIVETIMEOUT 60000 \
		/OPTSENDTIMEOUT 60000 \
		/URL "${url}" \
		/LOCAL "${local}" \
		/INTERNETFLAGS ${INTERNET_FLAG_RELOAD}|${INTERNET_FLAG_NO_CACHE_WRITE}|${INTERNET_FLAG_KEEP_CONNECTION}|${INTERNET_FLAG_NO_COOKIES}|${INTERNET_FLAG_NO_UI} \
		/SECURITYFLAGS ${SECURITY_FLAG_STRENGTH_STRONG} \
		${extra} \
		/END
	Pop $Download.ID
!macroend

Function DownloadWaitSilent
	NSxfer::Wait /ID $Download.ID /MODE SILENT /END
	NSxfer::Query /ID $Download.ID /ERRORCODE /ERRORTEXT /END
FunctionEnd

Function DownloadWait
	NSxfer::Wait /ID $Download.ID /MODE PAGE \
		/STATUSTEXT \
			"{TIMEREMAINING} left - {RECVSIZE} of {FILESIZE} ({SPEED})" \
			"{TIMEREMAINING} left - {TOTALRECVSIZE} of {TOTALFILESIZE} ({SPEED})" \
		/ABORT "Legacy Update" "Cancelling will terminate Legacy Update setup." \
		/END
	NSxfer::Query /ID $Download.ID /ERRORCODE /ERRORTEXT /END
FunctionEnd

!macro -Download name url filename verbose
	!insertmacro DetailPrint "Downloading ${name}..."
	!insertmacro DownloadRequest "${url}" "${filename}" ""
	${If} ${verbose} == 1
		Call DownloadWait
	${Else}
		Call DownloadWaitSilent
	${EndIf}
	Pop $1
	Pop $0
	${If} $0 != "OK"
		${If} $1 != ${ERROR_INTERNET_OPERATION_CANCELLED}
			MessageBox MB_USERICON "${name} failed to download.$\r$\n$\r$\n$0 ($1)" /SD IDOK
		${EndIf}
		Delete /REBOOTOK "${filename}"
		SetErrorLevel 1
		Abort
	${EndIf}
!macroend

!macro Download name url filename verbose
	${If} ${FileExists} "$EXEDIR\${filename}"
		${If} $OUTDIR != "$EXEDIR"
			SetOutPath "$EXEDIR"
		${EndIf}
		StrCpy $0 "$EXEDIR\${filename}"
	${Else}
		${If} $OUTDIR != "$RunOnceDir"
			SetOutPath "$RunOnceDir"
		${EndIf}
		${IfNot} ${FileExists} "$RunOnceDir\${filename}"
			!insertmacro -Download '${name}' '${url}' '$RunOnceDir\${filename}' ${verbose}
		${EndIf}
		StrCpy $0 "$RunOnceDir\${filename}"
	${EndIf}
!macroend

Var /GLOBAL Exec.Command
Var /GLOBAL Exec.Name
Var /GLOBAL Exec.IsWusa

Function ExecWithErrorHandling
	Push $0
	ExecWait '$Exec.Command' $0
	${If} $0 == ${ERROR_SUCCESS_REBOOT_REQUIRED}
		SetRebootFlag true
	${ElseIf} $0 == ${ERROR_INSTALL_USEREXIT}
		SetErrorLevel ${ERROR_INSTALL_USEREXIT}
		Abort
	${ElseIf} $Exec.IsWusa == 1
	${AndIf} $0 == 1
		; wusa exits with 1 if the patch is already installed. Treat this as success.
		DetailPrint "Installation skipped - already installed"
	${ElseIf} $Exec.IsWusa == 1
	${AndIf} $0 == ${WU_S_ALREADY_INSTALLED}
		DetailPrint "Installation skipped - already installed"
	${ElseIf} $Exec.IsWusa == 1
	${AndIf} $0 == ${WU_E_NOT_APPLICABLE}
		DetailPrint "Installation skipped - not applicable"
	${ElseIf} $0 != 0
		LegacyUpdateNSIS::MessageForHresult $0
		Pop $1
		MessageBox MB_USERICON "$Exec.Name failed to install.$\r$\n$\r$\n$1 ($0)" /SD IDOK
		SetErrorLevel $0
		Abort
	${EndIf}
	Pop $0
FunctionEnd

!macro ExecWithErrorHandling name command iswusa
	StrCpy $Exec.Command '${command}'
	StrCpy $Exec.Name '${name}'
	StrCpy $Exec.IsWusa '${iswusa}'
	Call ExecWithErrorHandling
!macroend

!macro Install name filename args
	!insertmacro DetailPrint "Installing ${name}..."
	!insertmacro ExecWithErrorHandling '${name}' '"$0" ${args}' 0
!macroend

!macro InstallSP name filename
	; SPInstall.exe /norestart seems to be broken. We let it do a delayed restart, then cancel it.
	!insertmacro DetailPrint "Extracting ${name}..."
	!insertmacro ExecWithErrorHandling '${name}' '"$0" /X:"$PLUGINSDIR\${filename}"' 0
	!insertmacro DetailPrint "Installing ${name}..."
	!insertmacro ExecWithErrorHandling '${name}' '"$PLUGINSDIR\${filename}\spinstall.exe" /unattend /nodialog /warnrestart:600' 0

	; If we successfully abort a shutdown, we'll get exit code 0, so we know a reboot is required.
	ExecWait "$WINDIR\system32\shutdown.exe /a" $0
	${If} $0 == 0
		SetRebootFlag true
	${EndIf}
!macroend

!macro DownloadMSU kbid name url
	!insertmacro Download '${name} (${kbid})' '${url}' '${kbid}.msu' 1
!macroend

!macro InstallMSU kbid name
	; Stop AU service before running wusa so it doesn't try checking for updates online first (which
	; may never complete before we install our patches).
	!insertmacro DetailPrint "Installing ${name} (${kbid})..."
	SetDetailsPrint none
	ExecShellWait "" "$WINDIR\system32\net.exe" "stop wuauserv" SW_HIDE
	SetDetailsPrint listonly
	!insertmacro ExecWithErrorHandling '${name} (${kbid})' '$WINDIR\system32\wusa.exe /quiet /norestart "$0"' 1
!macroend

!macro EnsureAdminRights
	${IfNot} ${AtLeastWin2000}
		MessageBox MB_USERICON "Legacy Update requires at least Windows 2000." /SD IDOK
		SetErrorLevel ${ERROR_OLD_WIN_VERSION}
		Quit
	${EndIf}

	System::Call '${IsUserAnAdmin}() .r0'
	${If} $0 == 0
		MessageBox MB_USERICON "Log on as an administrator to install Legacy Update." /SD IDOK
		SetErrorLevel ${ERROR_ELEVATION_REQUIRED}
		Quit
	${EndIf}
!macroend

!macro InhibitSleep state
	${If} ${state} == 1
		System::Call '${SetThreadExecutionState}(${ES_CONTINUOUS}|${ES_SYSTEM_REQUIRED})'
	${Else}
		System::Call '${SetThreadExecutionState}(${ES_CONTINUOUS})'
	${EndIf}
!macroend

!macro TryWithRetry command error
	ClearErrors
	${command}
	IfErrors 0 +3
		MessageBox MB_RETRYCANCEL|MB_USERICON \
			'${error}$\r$\n$\r$\nIf Internet Explorer is open, close it and click Retry.' \
			/SD IDCANCEL \
			IDRETRY -3
		Abort
!macroend

!macro TryFile file oname
	!insertmacro TryWithRetry `File "/ONAME=${oname}" "${file}"` 'Unable to write to "${oname}".'
!macroend

!macro TryDelete file
	!insertmacro TryWithRetry `Delete "${file}"` 'Unable to delete "${file}".'
!macroend

!macro TryRename src dest
	!insertmacro TryWithRetry `Rename "${src}" "${dest}"` 'Unable to write to "${dest}".'
!macroend

!macro RegisterDLL un arch file
	${If} "${un}" == "Un"
		StrCpy $0 "/u"
	${Else}
		StrCpy $0 ""
	${EndIf}

	${If} "${arch}" == "x64"
		${DisableX64FSRedirection}
	${EndIf}

	ClearErrors
	ExecWait '"$WINDIR\system32\regsvr32.exe" /s $0 "${file}"'
	${If} ${Errors}
		; Do it again non-silently so the user can see the error.
		ExecWait '"$WINDIR\system32\regsvr32.exe" $0 "${file}"'
		${If} "${arch}" == "x64"
			${EnableX64FSRedirection}
		${EndIf}
		Abort
	${EndIf}

	${If} "${arch}" == "x64"
		${EnableX64FSRedirection}
	${EndIf}
!macroend
