tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

stub.nsh (57207B)


      1 # This Source Code Form is subject to the terms of the Mozilla Public
      2 # License, v. 2.0. If a copy of the MPL was not distributed with this
      3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
      4 
      5 # Required Plugins:
      6 # AppAssocReg
      7 # CertCheck
      8 # InetBgDL
      9 # ShellLink
     10 # UAC
     11 
     12 ; Set verbosity to 3 (e.g. no script) to lessen the noise in the build logs
     13 !verbose 3
     14 
     15 SetDatablockOptimize on
     16 SetCompress off
     17 CRCCheck on
     18 
     19 RequestExecutionLevel user
     20 
     21 ManifestSupportedOS all
     22 ManifestDPIAware true
     23 
     24 !addplugindir ./
     25 
     26 Var CheckboxShortcuts
     27 Var CheckboxInstallMaintSvc
     28 Var CheckboxCleanupProfile
     29 
     30 Var FontFamilyName
     31 
     32 Var HasRequiredSpaceAvailable
     33 Var IsDownloadFinished
     34 Var DownloadSizeBytes
     35 Var DownloadReset
     36 Var ExistingTopDir
     37 Var SpaceAvailableBytes
     38 Var InitialInstallDir
     39 Var HandleDownload
     40 Var InstallCounterStep
     41 Var InstallTotalSteps
     42 Var ProgressCompleted
     43 Var UsingHighContrastMode
     44 
     45 Var ExitCode
     46 Var FirefoxLaunchCode
     47 
     48 Var StartDownloadPhaseTickCount
     49 ; Since the Intro and Options pages can be displayed multiple times the total
     50 ; seconds spent on each of these pages is reported.
     51 Var IntroPhaseSeconds
     52 Var OptionsPhaseSeconds
     53 ; The tick count for the last download.
     54 Var StartLastDownloadTickCount
     55 ; The number of seconds from the start of the download phase until the first
     56 ; bytes are received. This is only recorded for first request so it is possible
     57 ; to determine connection issues for the first request.
     58 Var DownloadFirstTransferSeconds
     59 ; The last four tick counts are for the end of a phase in the installation page.
     60 Var EndDownloadPhaseTickCount
     61 Var EndPreInstallPhaseTickCount
     62 Var EndInstallPhaseTickCount
     63 Var EndFinishPhaseTickCount
     64 
     65 Var DistributionID
     66 Var DistributionVersion
     67 Var WindowsUBR
     68 Var StubBuildID
     69 
     70 Var InitialInstallRequirementsCode
     71 Var ExistingProfile
     72 Var ExistingVersion
     73 Var ExistingBuildID
     74 Var DownloadedBytes
     75 Var DownloadRetryCount
     76 
     77 ; After a failure, did the user choose to open the download page as a fallback?
     78 Var OpenedDownloadPage
     79 
     80 Var DownloadServerIP
     81 Var PostSigningData
     82 Var PreviousInstallDir
     83 Var ProfileCleanupPromptType
     84 Var AppLaunchWaitTickCount
     85 Var TimerHandle
     86 
     87 ; Set AbortInstallation to "true" to prevent the installation "Pages" from starting, while still allowing
     88 ; SendPing and its OnPing callback to complete.
     89 Var AbortInstallation
     90 
     91 ; The SendPing function will set this to "true" once it has sent a ping, to ensure that we don't
     92 ; send multiple pings for the same installation.
     93 Var PingAlreadySent
     94 
     95 !define ARCH_X86 1
     96 !define ARCH_AMD64 2
     97 !define ARCH_AARCH64 3
     98 Var ArchToInstall
     99 
    100 ; Uncomment the following to prevent pinging the metrics server when testing
    101 ; the stub installer
    102 ;!define STUB_DEBUG
    103 
    104 !define StubURLVersion "v11"
    105 
    106 ; Successful install exit code
    107 !define ERR_SUCCESS 0
    108 
    109 ; Default failure exit code. Seeing this in telemetry indicates that the stub
    110 ; installer has exited unsuccessfully, but no reason has been specified
    111 !define ERR_UNKNOWN 1
    112 
    113 /**
    114 * The following errors prefixed with ERR_DOWNLOAD apply to the download phase.
    115 */
    116 ; The download was cancelled by the user
    117 !define ERR_DOWNLOAD_CANCEL 10
    118 
    119 ; Too many attempts to download. The maximum attempts is defined in
    120 ; DownloadMaxRetries.
    121 !define ERR_DOWNLOAD_TOO_MANY_RETRIES 11
    122 
    123 /**
    124 * The following errors prefixed with ERR_PREINSTALL apply to the pre-install
    125 * check phase.
    126 */
    127 ; Unable to acquire a file handle to the downloaded file
    128 !define ERR_PREINSTALL_INVALID_HANDLE 20
    129 
    130 ; The downloaded file's certificate is not trusted by the certificate store.
    131 !define ERR_PREINSTALL_CERT_UNTRUSTED 21
    132 
    133 ; The downloaded file's certificate attribute values were incorrect.
    134 !define ERR_PREINSTALL_CERT_ATTRIBUTES 22
    135 
    136 ; The downloaded file's certificate is not trusted by the certificate store and
    137 ; certificate attribute values were incorrect.
    138 !define ERR_PREINSTALL_CERT_UNTRUSTED_AND_ATTRIBUTES 23
    139 
    140 ; Timed out while waiting for the certificate checks to run.
    141 !define ERR_PREINSTALL_CERT_TIMEOUT 24
    142 
    143 ; System does not meet the minimum hardware requirements
    144 !define ERR_PREINSTALL_SYS_HW_REQ 25
    145 
    146 ; System does not meet the minimum OS version requirements
    147 !define ERR_PREINSTALL_SYS_OS_REQ 26
    148 
    149 ; Insufficient storage space is available in the target location
    150 !define ERR_PREINSTALL_SPACE 27
    151 
    152 ; Target location is not writable
    153 !define ERR_PREINSTALL_NOT_WRITABLE 28
    154 
    155 /**
    156 * The following errors prefixed with ERR_INSTALL apply to the install phase.
    157 */
    158 ; The installation timed out. The installation timeout is defined by the number
    159 ; of progress steps defined in InstallTotalSteps and the install timer
    160 ; interval defined in InstallIntervalMS
    161 !define ERR_INSTALL_TIMEOUT 30
    162 
    163 ; Maximum times to retry the download before displaying an error
    164 !define DownloadMaxRetries 9
    165 
    166 ; Interval before retrying to download. 3 seconds is used along with 10
    167 ; attempted downloads (the first attempt along with 9 retries) to give a
    168 ; minimum of 30 seconds or retrying before giving up.
    169 !define DownloadRetryIntervalMS 3000
    170 
    171 ; Interval for the download timer
    172 !define DownloadIntervalMS 200
    173 
    174 ; Timeout for the certificate check
    175 !define PreinstallCertCheckMaxWaitSec 30
    176 
    177 ; Interval for the install timer
    178 !define InstallIntervalMS 100
    179 
    180 ; Number of steps for the install progress.
    181 ; This might not be enough when installing on a slow network drive so it will
    182 ; fallback to downloading the full installer if it reaches this number.
    183 
    184 ; Approximately 240 seconds with a 100 millisecond timer.
    185 !define InstallCleanTotalSteps 2400
    186 
    187 ; Approximately 255 seconds with a 100 millisecond timer.
    188 !define InstallPaveOverTotalSteps 2550
    189 
    190 ; Blurb duty cycle
    191 !define BlurbDisplayMS 19500
    192 !define BlurbBlankMS 500
    193 
    194 ; Interval between checks for the application window and progress bar updates.
    195 !define AppLaunchWaitIntervalMS 100
    196 
    197 ; Total time to wait for the application to start before just exiting.
    198 !define AppLaunchWaitTimeoutMS 10000
    199 
    200 ; Maximum value of the download/install/launch progress bar, and the end values
    201 ; for each individual stage.
    202 !define PROGRESS_BAR_TOTAL_STEPS 500
    203 !define PROGRESS_BAR_DOWNLOAD_END_STEP 300
    204 !define PROGRESS_BAR_INSTALL_END_STEP 475
    205 !define PROGRESS_BAR_APP_LAUNCH_END_STEP 500
    206 
    207 ; Amount of physical memory required for the 64-bit build to be selected (2 GB).
    208 ; Machines with this or less RAM get the 32-bit build, even with a 64-bit OS.
    209 !define RAM_NEEDED_FOR_64BIT 0x80000000
    210 
    211 ; Attempt to elevate Standard Users in addition to users that
    212 ; are a member of the Administrators group.
    213 !define NONADMIN_ELEVATE
    214 
    215 !define CONFIG_INI "config.ini"
    216 !define PARTNER_INI "$EXEDIR\partner.ini"
    217 
    218 !ifndef FILE_SHARE_READ
    219  !define FILE_SHARE_READ 1
    220 !endif
    221 !ifndef GENERIC_READ
    222  !define GENERIC_READ 0x80000000
    223 !endif
    224 !ifndef OPEN_EXISTING
    225  !define OPEN_EXISTING 3
    226 !endif
    227 !ifndef INVALID_HANDLE_VALUE
    228  !define INVALID_HANDLE_VALUE -1
    229 !endif
    230 
    231 !define DefaultInstDir32bit "$PROGRAMFILES32\${BrandFullName}"
    232 !define DefaultInstDir64bit "$PROGRAMFILES64\${BrandFullName}"
    233 
    234 !insertmacro GetParameters
    235 !insertmacro GetOptions
    236 !insertmacro LineFind
    237 !insertmacro StrFilter
    238 
    239 !include "locales.nsi"
    240 !include "branding.nsi"
    241 
    242 !include "defines.nsi"
    243 
    244 ; Must be included after defines.nsi
    245 !include "locale-fonts.nsh"
    246 
    247 ; The OFFICIAL define is a workaround to support different urls for Release and
    248 ; Beta since they share the same branding when building with other branches that
    249 ; set the update channel to beta.
    250 !ifdef OFFICIAL
    251 !ifdef BETA_UPDATE_CHANNEL
    252 !undef URLStubDownloadX86
    253 !undef URLStubDownloadAMD64
    254 !undef URLStubDownloadAArch64
    255 !define URLStubDownloadX86 "https://download.mozilla.org/?os=win&lang=${AB_CD}&product=firefox-beta-latest"
    256 !define URLStubDownloadAMD64 "https://download.mozilla.org/?os=win64&lang=${AB_CD}&product=firefox-beta-latest"
    257 !define URLStubDownloadAArch64 "https://download.mozilla.org/?os=win64-aarch64&lang=${AB_CD}&product=firefox-beta-latest"
    258 !undef URLManualDownload
    259 !define URLManualDownload "https://www.mozilla.org/${AB_CD}/firefox/installer-help/?channel=beta&installer_lang=${AB_CD}"
    260 !undef Channel
    261 !define Channel "beta"
    262 !endif
    263 !endif
    264 
    265 !include "common.nsh"
    266 
    267 
    268 !insertmacro CopyPostSigningData
    269 !insertmacro ElevateUAC
    270 !insertmacro GetLongPath
    271 !insertmacro GetPathFromString
    272 !insertmacro GetParent
    273 !insertmacro GetSingleInstallPath
    274 !insertmacro InitHashAppModelId
    275 !insertmacro IsUserAdmin
    276 !insertmacro RemovePrecompleteEntries
    277 !insertmacro SetBrandNameVars
    278 !insertmacro ITBL3Create
    279 !insertmacro UnloadUAC
    280 
    281 VIAddVersionKey "FileDescription" "${BrandShortName} Installer"
    282 VIAddVersionKey "OriginalFilename" "setup-stub.exe"
    283 
    284 Name "$BrandFullName"
    285 
    286 XPStyle on
    287 BrandingText " "
    288 ChangeUI IDD_INST "nsisui.exe"
    289 
    290 !ifdef ${AB_CD}_rtl
    291  LoadLanguageFile "locale-rtl.nlf"
    292 !else
    293  LoadLanguageFile "locale.nlf"
    294 !endif
    295 
    296 !include "nsisstrings.nlf"
    297 
    298 Caption "$(INSTALLER_WIN_CAPTION)"
    299 
    300 !macro _RegisterAllCustomFunctions
    301  GetFunctionAddress $0 getUIString
    302  WebBrowser::RegisterCustomFunction $0 "getUIString"
    303 
    304  GetFunctionAddress $0 getTextDirection
    305  WebBrowser::RegisterCustomFunction $0 "getTextDirection"
    306 
    307  GetFunctionAddress $0 getFontName
    308  WebBrowser::RegisterCustomFunction $0 "getFontName"
    309 
    310  GetFunctionAddress $0 getIsHighContrast
    311  WebBrowser::RegisterCustomFunction $0 "getIsHighContrast"
    312 
    313  GetFunctionAddress $0 gotoInstallPage
    314  WebBrowser::RegisterCustomFunction $0 "gotoInstallPage"
    315 
    316  GetFunctionAddress $0 getProgressBarPercent
    317  WebBrowser::RegisterCustomFunction $0 "getProgressBarPercent"
    318 !macroend
    319 !define RegisterAllCustomFunctions "!insertmacro _RegisterAllCustomFunctions"
    320 
    321 !macro _StartTimer _INTERVAL_MS _FUNCTION_NAME
    322  Push $0
    323  GetFunctionAddress $0 ${_FUNCTION_NAME}
    324  WebBrowser::CreateTimer $0 ${_INTERVAL_MS}
    325  Pop $TimerHandle
    326  Pop $0
    327 !macroend
    328 !define StartTimer "!insertmacro _StartTimer"
    329 
    330 Function gotoInstallPage
    331  Pop $0
    332  StrCpy $CheckboxCleanupProfile $0
    333 
    334  StrCpy $R9 1
    335  Call RelativeGotoPage
    336  Push $0
    337 FunctionEnd
    338 
    339 Function getProgressBarPercent
    340  ; Custom functions always get one parameter, which we don't use here.
    341  ; But we will use $0 as a scratch accumulator register.
    342  Pop $0
    343  ; This math is getting the progess bar completion fraction and converting it
    344  ; to a percentage, but we implement that with the operations in the reverse
    345  ; of the intuitive order so that our integer math doesn't truncate to zero.
    346  IntOp $0 $ProgressCompleted * 100
    347  IntOp $0 $0 / ${PROGRESS_BAR_TOTAL_STEPS}
    348  Push $0
    349 FunctionEnd
    350 
    351 Function getTextDirection
    352  Pop $0
    353  !ifdef ${AB_CD}_rtl
    354    Push "rtl"
    355  !else
    356    Push "ltr"
    357  !endif
    358 FunctionEnd
    359 
    360 Function getFontName
    361  Pop $0
    362  Push $FontFamilyName
    363 FunctionEnd
    364 
    365 Function getIsHighContrast
    366  Pop $0
    367  Push $UsingHighContrastMode
    368 FunctionEnd
    369 
    370 Function getUIString
    371  Pop $0
    372  ${Select} $0
    373    ${Case} "cleanup_header"
    374      ${If} $ProfileCleanupPromptType == 1
    375        Push "$(STUB_CLEANUP_REINSTALL_HEADER3)"
    376      ${Else}
    377        Push "$(STUB_CLEANUP_PAVEOVER_HEADER3)"
    378      ${EndIf}
    379    ${Case} "cleanup_button"
    380      ${If} $ProfileCleanupPromptType == 1
    381        Push "$(STUB_CLEANUP_REINSTALL_BUTTON2)"
    382      ${Else}
    383        Push "$(STUB_CLEANUP_PAVEOVER_BUTTON2)"
    384      ${EndIf}
    385    ${Case} "cleanup_checkbox"
    386      Push "$(STUB_CLEANUP_CHECKBOX_LABEL3)"
    387    ${Case} "installing_label"
    388      Push "$(STUB_INSTALLING_LABEL2)"
    389    ${Case} "installing_blurb_0"
    390      !ifdef DEV_EDITION
    391        Push "$(STUB_BLURB_FIRST2_DEVEDITION)"
    392      !else
    393        Push "$(STUB_BLURB_FIRST2)"
    394      !endif
    395    ${Case} "installing_blurb_1"
    396      !ifdef DEV_EDITION
    397        Push "$(STUB_BLURB_SECOND2_DEVEDITION)"
    398      !else
    399        Push "$(STUB_BLURB_SECOND2)"
    400      !endif
    401    ${Case} "installing_blurb_2"
    402      !ifdef DEV_EDITION
    403        Push "$(STUB_BLURB_THIRD2_DEVEDITION)"
    404      !else
    405        Push "$(STUB_BLURB_THIRD2)"
    406      !endif
    407    ${Default}
    408      Push ""
    409  ${EndSelect}
    410 FunctionEnd
    411 
    412 Function createProfileCleanup
    413  ${If} $AbortInstallation != "false"
    414    ; Abort in this context skips the "page"
    415    Abort
    416  ${EndIf}
    417  Call ShouldPromptForProfileCleanup
    418 
    419  ${If} $ProfileCleanupPromptType == 0
    420    StrCpy $CheckboxCleanupProfile 0
    421    Abort ; Skip this page
    422  ${EndIf}
    423 
    424  ${RegisterAllCustomFunctions}
    425 
    426  File /oname=$PLUGINSDIR\profile_cleanup.html "profile_cleanup.html"
    427  File /oname=$PLUGINSDIR\profile_cleanup_page.css "profile_cleanup_page.css"
    428  File /oname=$PLUGINSDIR\profile_cleanup.js "profile_cleanup.js"
    429  WebBrowser::ShowPage "$PLUGINSDIR\profile_cleanup.html"
    430 FunctionEnd
    431 
    432 Function createInstall
    433  ${If} $AbortInstallation != "false"
    434    ; Skip the installation, but first send the telemetry
    435    Call SendPing
    436    ; Abort in this context skips the "page"
    437    Abort
    438  ${EndIf}
    439  GetDlgItem $0 $HWNDPARENT 1 ; Install button
    440  EnableWindow $0 0
    441  ShowWindow $0 ${SW_HIDE}
    442 
    443  GetDlgItem $0 $HWNDPARENT 3 ; Back button
    444  EnableWindow $0 0
    445  ShowWindow $0 ${SW_HIDE}
    446 
    447  GetDlgItem $0 $HWNDPARENT 2 ; Cancel button
    448  ; Hide the Cancel button, but don't disable it (or else it won't be possible
    449  ; to close the window)
    450  ShowWindow $0 ${SW_HIDE}
    451 
    452  ; Get keyboard focus on the parent
    453  System::Call "user32::SetFocus(p$HWNDPARENT)"
    454 
    455  ; Set $DownloadReset to true so the first download tick count is measured.
    456  StrCpy $DownloadReset "true"
    457  StrCpy $IsDownloadFinished "false"
    458  StrCpy $DownloadRetryCount "0"
    459  StrCpy $DownloadedBytes "0"
    460  StrCpy $StartLastDownloadTickCount ""
    461  StrCpy $DownloadFirstTransferSeconds ""
    462  StrCpy $OpenedDownloadPage "0"
    463 
    464  ClearErrors
    465  ReadINIStr $ExistingVersion "$INSTDIR\application.ini" "App" "Version"
    466  ${If} ${Errors}
    467    StrCpy $ExistingVersion "0"
    468  ${EndIf}
    469 
    470  ClearErrors
    471  ReadINIStr $ExistingBuildID "$INSTDIR\application.ini" "App" "BuildID"
    472  ${If} ${Errors}
    473    StrCpy $ExistingBuildID "0"
    474  ${EndIf}
    475 
    476  ${GetLocalAppDataFolder} $0
    477  ${If} ${FileExists} "$0\Mozilla\Firefox"
    478    StrCpy $ExistingProfile "1"
    479  ${Else}
    480    StrCpy $ExistingProfile "0"
    481  ${EndIf}
    482 
    483  StrCpy $DownloadServerIP ""
    484 
    485  System::Call "kernel32::GetTickCount()l .s"
    486  Pop $StartDownloadPhaseTickCount
    487 
    488  ${If} ${FileExists} "$INSTDIR\uninstall\uninstall.log"
    489    StrCpy $InstallTotalSteps ${InstallPaveOverTotalSteps}
    490  ${Else}
    491    StrCpy $InstallTotalSteps ${InstallCleanTotalSteps}
    492  ${EndIf}
    493 
    494  ${ITBL3Create}
    495  ${ITBL3SetProgressState} "${TBPF_INDETERMINATE}"
    496 
    497  ; Make sure the file we're about to try to download to doesn't already exist,
    498  ; so we don't end up trying to "resume" on top of the wrong file.
    499  Delete "$PLUGINSDIR\download.exe"
    500 
    501  ${StartTimer} ${DownloadIntervalMS} StartDownload
    502 
    503  ${RegisterAllCustomFunctions}
    504 
    505  File /oname=$PLUGINSDIR\installing.html "installing.html"
    506  File /oname=$PLUGINSDIR\installing_page.css "installing_page.css"
    507  File /oname=$PLUGINSDIR\installing.js "installing.js"
    508  WebBrowser::ShowPage "$PLUGINSDIR\installing.html"
    509 FunctionEnd
    510 
    511 Function StartDownload
    512  WebBrowser::CancelTimer $TimerHandle
    513 
    514  Call GetDownloadURL
    515  Pop $0
    516  InetBgDL::Get "$0" "$PLUGINSDIR\download.exe" \
    517                /CONNECTTIMEOUT 120 /RECEIVETIMEOUT 120 /END
    518 
    519  ${StartTimer} ${DownloadIntervalMS} OnDownload
    520 
    521  ${If} ${FileExists} "$INSTDIR\${TO_BE_DELETED}"
    522    RmDir /r "$INSTDIR\${TO_BE_DELETED}"
    523  ${EndIf}
    524 FunctionEnd
    525 
    526 Function SetProgressBars
    527  ${ITBL3SetProgressValue} "$ProgressCompleted" "${PROGRESS_BAR_TOTAL_STEPS}"
    528 FunctionEnd
    529 
    530 Function OnDownload
    531  InetBgDL::GetStats
    532  # $0 = HTTP status code, 0=Completed
    533  # $1 = Completed files
    534  # $2 = Remaining files
    535  # $3 = Number of downloaded bytes for the current file
    536  # $4 = Size of current file (Empty string if the size is unknown)
    537  # /RESET must be used if status $0 > 299 (e.g. failure), even if resuming
    538  # When status is $0 =< 299 it is handled by InetBgDL
    539  StrCpy $DownloadServerIP "$5"
    540  ${If} $0 > 299
    541    WebBrowser::CancelTimer $TimerHandle
    542    IntOp $DownloadRetryCount $DownloadRetryCount + 1
    543    ${If} $DownloadRetryCount >= ${DownloadMaxRetries}
    544      StrCpy $ExitCode "${ERR_DOWNLOAD_TOO_MANY_RETRIES}"
    545      ; Use a timer so the UI has a chance to update
    546      ${StartTimer} ${InstallIntervalMS} DisplayDownloadError
    547      Return
    548    ${EndIf}
    549 
    550    ; 1000 is a special code meaning InetBgDL lost the connection before it got
    551    ; all the bytes it was expecting. We'll try to resume the transfer in that
    552    ; case (assuming we aren't out of retries), so don't treat it as a reset
    553    ; or clear the progress bar.
    554    ${If} $0 != 1000
    555      ${If} "$DownloadReset" != "true"
    556        StrCpy $DownloadedBytes "0"
    557        ${ITBL3SetProgressState} "${TBPF_INDETERMINATE}"
    558      ${EndIf}
    559      StrCpy $DownloadSizeBytes ""
    560      StrCpy $DownloadReset "true"
    561      Delete "$PLUGINSDIR\download.exe"
    562    ${EndIf}
    563 
    564    InetBgDL::Get /RESET /END
    565    ${StartTimer} ${DownloadRetryIntervalMS} StartDownload
    566    Return
    567  ${EndIf}
    568 
    569  ${If} "$DownloadReset" == "true"
    570    System::Call "kernel32::GetTickCount()l .s"
    571    Pop $StartLastDownloadTickCount
    572    StrCpy $DownloadReset "false"
    573    ; The seconds elapsed from the start of the download phase until the first
    574    ; bytes are received are only recorded for the first request so it is
    575    ; possible to determine connection issues for the first request.
    576    ${If} "$DownloadFirstTransferSeconds" == ""
    577      ; Get the seconds elapsed from the start of the download phase until the
    578      ; first bytes are received.
    579      ${GetSecondsElapsed} "$StartDownloadPhaseTickCount" "$StartLastDownloadTickCount" $DownloadFirstTransferSeconds
    580    ${EndIf}
    581  ${EndIf}
    582 
    583  ${If} "$DownloadSizeBytes" == ""
    584  ${AndIf} "$4" != ""
    585    StrCpy $DownloadSizeBytes "$4"
    586    StrCpy $ProgressCompleted 0
    587  ${EndIf}
    588 
    589  ; Don't update the status until after the download starts
    590  ${If} $2 != 0
    591  ${AndIf} "$4" == ""
    592    Return
    593  ${EndIf}
    594 
    595  ${If} $IsDownloadFinished != "true"
    596    ${If} $2 == 0
    597      WebBrowser::CancelTimer $TimerHandle
    598      StrCpy $IsDownloadFinished "true"
    599      System::Call "kernel32::GetTickCount()l .s"
    600      Pop $EndDownloadPhaseTickCount
    601 
    602      ${If} "$DownloadSizeBytes" == ""
    603        ; It's possible for the download to finish before we were able to
    604        ; get the size while it was downloading, and InetBgDL doesn't report
    605        ; it afterwards. Use the size of the finished file.
    606        ClearErrors
    607        FileOpen $5 "$PLUGINSDIR\download.exe" r
    608        ${IfNot} ${Errors}
    609          FileSeek $5 0 END $DownloadSizeBytes
    610          FileClose $5
    611        ${EndIf}
    612      ${EndIf}
    613      StrCpy $DownloadedBytes "$DownloadSizeBytes"
    614 
    615      ; Update the progress bars first in the UI change so they take affect
    616      ; before other UI changes.
    617      StrCpy $ProgressCompleted "${PROGRESS_BAR_DOWNLOAD_END_STEP}"
    618      Call SetProgressBars
    619 
    620      ; Disable the Cancel button during the install
    621      GetDlgItem $5 $HWNDPARENT 2
    622      EnableWindow $5 0
    623 
    624      ; Open a handle to prevent modification of the full installer
    625      StrCpy $R9 "${INVALID_HANDLE_VALUE}"
    626      System::Call 'kernel32::CreateFileW(w "$PLUGINSDIR\download.exe", \
    627                                          i ${GENERIC_READ}, \
    628                                          i ${FILE_SHARE_READ}, i 0, \
    629                                          i ${OPEN_EXISTING}, i 0, i 0) i .R9'
    630      StrCpy $HandleDownload "$R9"
    631 
    632      ${If} $HandleDownload == ${INVALID_HANDLE_VALUE}
    633        StrCpy $ExitCode "${ERR_PREINSTALL_INVALID_HANDLE}"
    634        System::Call "kernel32::GetTickCount()l .s"
    635        Pop $EndPreInstallPhaseTickCount
    636        ; Use a timer so the UI has a chance to update
    637        ${StartTimer} ${InstallIntervalMS} DisplayDownloadError
    638      ${Else}
    639        CertCheck::CheckPETrustAndInfoAsync "$PLUGINSDIR\download.exe" \
    640          "${CertNameDownload}" "${CertIssuerDownload}"
    641        ${StartTimer} ${DownloadIntervalMS} OnCertCheck
    642      ${EndIf}
    643    ${Else}
    644      StrCpy $DownloadedBytes "$3"
    645      System::Int64Op $DownloadedBytes * ${PROGRESS_BAR_DOWNLOAD_END_STEP}
    646      Pop $ProgressCompleted
    647      System::Int64Op $ProgressCompleted / $DownloadSizeBytes
    648      Pop $ProgressCompleted
    649      Call SetProgressBars
    650    ${EndIf}
    651  ${EndIf}
    652 FunctionEnd
    653 
    654 Function OnCertCheck
    655  System::Call "kernel32::GetTickCount()l .s"
    656  Pop $EndPreInstallPhaseTickCount
    657 
    658  CertCheck::GetStatus
    659  Pop $0
    660  ${If} $0 == 0
    661    ${GetSecondsElapsed} "$EndDownloadPhaseTickCount" "$EndPreInstallPhaseTickCount" $0
    662    ${If} $0 >= ${PreinstallCertCheckMaxWaitSec}
    663      WebBrowser::CancelTimer $TimerHandle
    664      StrCpy $ExitCode "${ERR_PREINSTALL_CERT_TIMEOUT}"
    665      ; Use a timer so the UI has a chance to update
    666      ${StartTimer} ${InstallIntervalMS} DisplayDownloadError
    667    ${EndIf}
    668    Return
    669  ${EndIf}
    670  Pop $0
    671  Pop $1
    672 
    673  ${If} $0 == 0
    674  ${AndIf} $1 == 0
    675    StrCpy $ExitCode "${ERR_PREINSTALL_CERT_UNTRUSTED_AND_ATTRIBUTES}"
    676  ${ElseIf} $0 == 0
    677    StrCpy $ExitCode "${ERR_PREINSTALL_CERT_UNTRUSTED}"
    678  ${ElseIf} $1 == 0
    679    StrCpy $ExitCode "${ERR_PREINSTALL_CERT_ATTRIBUTES}"
    680  ${EndIf}
    681 
    682  WebBrowser::CancelTimer $TimerHandle
    683 
    684  ${If} $0 == 0
    685  ${OrIf} $1 == 0
    686    ; Use a timer so the UI has a chance to update
    687    ${StartTimer} ${InstallIntervalMS} DisplayDownloadError
    688    Return
    689  ${EndIf}
    690 
    691  Call LaunchFullInstaller
    692 FunctionEnd
    693 
    694 Function LaunchFullInstaller
    695  ; Instead of extracting the files we use the downloaded installer to
    696  ; install in case it needs to perform operations that the stub doesn't
    697  ; know about.
    698  WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "InstallDirectoryPath" "$INSTDIR"
    699 
    700  ; Always create a start menu shortcut, so the user always has some way
    701  ; to access the application.
    702  WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "StartMenuShortcuts" "true"
    703 
    704  ; Either avoid or force adding a taskbar pin and desktop shortcut
    705  ; based on the checkbox value.
    706  ${If} $CheckboxShortcuts == 0
    707    WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "TaskbarShortcut" "false"
    708    WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "DesktopShortcut" "false"
    709    WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "DesktopLauncher" "false"
    710  ${Else}
    711    WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "TaskbarShortcut" "true"
    712 !ifdef DESKTOP_LAUNCHER_ENABLED
    713    WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "DesktopShortcut" "false"
    714    WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "DesktopLauncher" "true"
    715 !else
    716    WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "DesktopShortcut" "true"
    717    WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "DesktopLauncher" "false"
    718 !endif
    719  ${EndIf}
    720 
    721 !ifdef MOZ_MAINTENANCE_SERVICE
    722  ${If} $CheckboxInstallMaintSvc == 1
    723    WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "MaintenanceService" "true"
    724  ${Else}
    725    WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "MaintenanceService" "false"
    726  ${EndIf}
    727 !else
    728  WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "MaintenanceService" "false"
    729 !endif
    730 
    731  ; Delete the taskbar shortcut history to ensure we do the right thing based on
    732  ; the config file above.
    733  ${GetShortcutsLogPath} $0
    734  Delete "$0"
    735 
    736  ${RemovePrecompleteEntries} "false"
    737 
    738  ; Delete the install.log and let the full installer create it. When the
    739  ; installer closes it we can detect that it has completed.
    740  Delete "$INSTDIR\install.log"
    741 
    742  ; Delete firefox.exe.moz-upgrade and firefox.exe.moz-delete if it exists
    743  ; since it being present will require an OS restart for the full
    744  ; installer.
    745  Delete "$INSTDIR\${FileMainEXE}.moz-upgrade"
    746  Delete "$INSTDIR\${FileMainEXE}.moz-delete"
    747 
    748  System::Call "kernel32::GetTickCount()l .s"
    749  Pop $EndPreInstallPhaseTickCount
    750 
    751  Exec "$\"$PLUGINSDIR\download.exe$\" /LaunchedFromStub /INI=$PLUGINSDIR\${CONFIG_INI}"
    752  ${StartTimer} ${InstallIntervalMS} CheckInstall
    753 FunctionEnd
    754 
    755 Function SendPing
    756  HideWindow
    757 
    758  ${If} $PingAlreadySent == "false"
    759    StrCpy $PingAlreadySent "true"
    760    ; Get the tick count for the completion of all phases.
    761    System::Call "kernel32::GetTickCount()l .s"
    762    Pop $EndFinishPhaseTickCount
    763 
    764    ; When the value of $IsDownloadFinished is false the download was started
    765    ; but didn't finish. In this case the tick count stored in
    766    ; $EndFinishPhaseTickCount is used to determine how long the download was
    767    ; in progress.
    768    ${If} "$IsDownloadFinished" == "false"
    769      StrCpy $EndDownloadPhaseTickCount "$EndFinishPhaseTickCount"
    770      ; Cancel the download in progress
    771      InetBgDL::Get /RESET /END
    772    ${EndIf}
    773 
    774 
    775    ; When $DownloadFirstTransferSeconds equals an empty string the download
    776    ; never successfully started so set the value to 0. It will be possible to
    777    ; determine that the download didn't successfully start from the seconds for
    778    ; the last download.
    779    ${If} "$DownloadFirstTransferSeconds" == ""
    780      StrCpy $DownloadFirstTransferSeconds "0"
    781    ${EndIf}
    782 
    783    ; When $StartLastDownloadTickCount equals an empty string the download never
    784    ; successfully started so set the value to $EndDownloadPhaseTickCount to
    785    ; compute the correct value.
    786    ${If} $StartLastDownloadTickCount == ""
    787      ; This could happen if the download never successfully starts
    788      StrCpy $StartLastDownloadTickCount "$EndDownloadPhaseTickCount"
    789    ${EndIf}
    790 
    791    ; When $EndPreInstallPhaseTickCount equals 0 the installation phase was
    792    ; never completed so set its value to $EndFinishPhaseTickCount to compute
    793    ; the correct value.
    794    ${If} "$EndPreInstallPhaseTickCount" == "0"
    795      StrCpy $EndPreInstallPhaseTickCount "$EndFinishPhaseTickCount"
    796    ${EndIf}
    797 
    798    ; When $EndInstallPhaseTickCount equals 0 the installation phase was never
    799    ; completed so set its value to $EndFinishPhaseTickCount to compute the
    800    ; correct value.
    801    ${If} "$EndInstallPhaseTickCount" == "0"
    802      StrCpy $EndInstallPhaseTickCount "$EndFinishPhaseTickCount"
    803    ${EndIf}
    804 
    805    ; Get the seconds elapsed from the start of the download phase to the end of
    806    ; the download phase.
    807    ${GetSecondsElapsed} "$StartDownloadPhaseTickCount" "$EndDownloadPhaseTickCount" $0
    808 
    809    ; Get the seconds elapsed from the start of the last download to the end of
    810    ; the last download.
    811    ${GetSecondsElapsed} "$StartLastDownloadTickCount" "$EndDownloadPhaseTickCount" $1
    812 
    813    ; Get the seconds elapsed from the end of the download phase to the
    814    ; completion of the pre-installation check phase.
    815    ${GetSecondsElapsed} "$EndDownloadPhaseTickCount" "$EndPreInstallPhaseTickCount" $2
    816 
    817    ; Get the seconds elapsed from the end of the pre-installation check phase
    818    ; to the completion of the installation phase.
    819    ${GetSecondsElapsed} "$EndPreInstallPhaseTickCount" "$EndInstallPhaseTickCount" $3
    820 
    821    ; Get the seconds elapsed from the end of the installation phase to the
    822    ; completion of all phases.
    823    ${GetSecondsElapsed} "$EndInstallPhaseTickCount" "$EndFinishPhaseTickCount" $4
    824 
    825    ${If} $ArchToInstall == ${ARCH_AMD64}
    826    ${OrIf} $ArchToInstall == ${ARCH_AARCH64}
    827      StrCpy $R0 "1"
    828    ${Else}
    829      StrCpy $R0 "0"
    830    ${EndIf}
    831 
    832    ${If} ${IsNativeAMD64}
    833    ${OrIf} ${IsNativeARM64}
    834      StrCpy $R1 "1"
    835    ${Else}
    836      StrCpy $R1 "0"
    837    ${EndIf}
    838 
    839    ; Though these values are sometimes incorrect due to bug 444664 it happens
    840    ; so rarely it isn't worth working around it by reading the registry values.
    841    ${WinVerGetMajor} $5
    842    ${WinVerGetMinor} $6
    843    ${WinVerGetBuild} $7
    844    ${WinVerGetServicePackLevel} $8
    845    ${If} ${IsServerOS}
    846      StrCpy $9 "1"
    847    ${Else}
    848      StrCpy $9 "0"
    849    ${EndIf}
    850 
    851    ${If} "$ExitCode" == "${ERR_SUCCESS}"
    852      ReadINIStr $R5 "$INSTDIR\application.ini" "App" "Version"
    853      ReadINIStr $R6 "$INSTDIR\application.ini" "App" "BuildID"
    854    ${Else}
    855      StrCpy $R5 "0"
    856      StrCpy $R6 "0"
    857    ${EndIf}
    858 
    859    ; Capture the distribution ID and version if it exists.
    860    ${If} ${FileExists} "$INSTDIR\distribution\distribution.ini"
    861      ReadINIStr $DistributionID "$INSTDIR\distribution\distribution.ini" "Global" "id"
    862      ReadINIStr $DistributionVersion "$INSTDIR\distribution\distribution.ini" "Global" "version"
    863    ${Else}
    864      StrCpy $DistributionID "0"
    865      StrCpy $DistributionVersion "0"
    866    ${EndIf}
    867 
    868    ; Capture the Windows UBR
    869    ReadRegDWORD $WindowsUBR HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" "UBR"
    870    ${If} ${Errors}
    871      StrCpy $WindowsUBR "-1" ; Assign -1 if an error occured during registry read
    872    ${EndIf}
    873    
    874    ; Capture the stub installer build ID
    875    StrCpy $StubBuildID ${MOZ_BUILDID}
    876 
    877    ; Whether installed into the default installation directory
    878    ${GetLongPath} "$INSTDIR" $R7
    879    ${GetLongPath} "$InitialInstallDir" $R8
    880    ${If} "$R7" == "$R8"
    881      StrCpy $R7 "1"
    882    ${Else}
    883      StrCpy $R7 "0"
    884    ${EndIf}
    885 
    886    ClearErrors
    887    WriteRegStr HKLM "Software\Mozilla" "${BrandShortName}InstallerTest" \
    888                     "Write Test"
    889    ${If} ${Errors}
    890      StrCpy $R8 "0"
    891    ${Else}
    892      DeleteRegValue HKLM "Software\Mozilla" "${BrandShortName}InstallerTest"
    893      StrCpy $R8 "1"
    894    ${EndIf}
    895 
    896    ${If} "$DownloadServerIP" == ""
    897      StrCpy $DownloadServerIP "Unknown"
    898    ${EndIf}
    899 
    900    StrCpy $R2 ""
    901    SetShellVarContext current ; Set SHCTX to the current user
    902    ReadRegStr $R2 HKCU "Software\Classes\http\shell\open\command" ""
    903    ${If} $R2 != ""
    904      ${GetPathFromString} "$R2" $R2
    905      ${GetParent} "$R2" $R3
    906      ${GetLongPath} "$R3" $R3
    907      ${If} $R3 == $INSTDIR
    908        StrCpy $R2 "1" ; This Firefox install is set as default.
    909      ${Else}
    910        StrCpy $R2 "$R2" "" -11 # length of firefox.exe
    911        ${If} "$R2" == "${FileMainEXE}"
    912          StrCpy $R2 "2" ; Another Firefox install is set as default.
    913        ${Else}
    914          StrCpy $R2 "0"
    915        ${EndIf}
    916      ${EndIf}
    917    ${Else}
    918      StrCpy $R2 "0" ; Firefox is not set as default.
    919    ${EndIf}
    920 
    921    ${If} "$R2" == "0"
    922      StrCpy $R3 ""
    923      ReadRegStr $R2 HKLM "Software\Classes\http\shell\open\command" ""
    924      ${If} $R2 != ""
    925        ${GetPathFromString} "$R2" $R2
    926        ${GetParent} "$R2" $R3
    927        ${GetLongPath} "$R3" $R3
    928        ${If} $R3 == $INSTDIR
    929          StrCpy $R2 "1" ; This Firefox install is set as default.
    930        ${Else}
    931          StrCpy $R2 "$R2" "" -11 # length of firefox.exe
    932          ${If} "$R2" == "${FileMainEXE}"
    933            StrCpy $R2 "2" ; Another Firefox install is set as default.
    934          ${Else}
    935            StrCpy $R2 "0"
    936          ${EndIf}
    937        ${EndIf}
    938      ${Else}
    939        StrCpy $R2 "0" ; Firefox is not set as default.
    940      ${EndIf}
    941    ${EndIf}
    942 
    943    ${GetParameters} $R9
    944    ClearErrors
    945    ${GetOptions} "$R9" "/LaunchedBy:" "$R4"
    946    ${If} ${Errors}
    947      StrCpy $R4 "unknown"
    948    ${EndIf}
    949 
    950    StrCpy $R3 "1"
    951 
    952 ; Note: ExitCode gets parsed here to determine values for "succeeded",
    953 ; "user_cancelled", etc.
    954 ; https://github.com/mozilla/gcp-ingestion/blob/1d9dc42384ebe3b0c7b0b2c193416d1534b7e444/ingestion-beam/src/main/java/com/mozilla/telemetry/decoder/ParseUri.java#L266
    955 
    956 !ifdef STUB_DEBUG
    957    MessageBox MB_OK "${BaseURLStubPing} \
    958                      $\nStub URL Version = ${StubURLVersion}${StubURLVersionAppend} \
    959                      $\nBuild Channel = ${Channel} \
    960                      $\nUpdate Channel = ${UpdateChannel} \
    961                      $\nLocale = ${AB_CD} \
    962                      $\nFirefox x64 = $R0 \
    963                      $\nRunning x64 Windows = $R1 \
    964                      $\nMajor = $5 \
    965                      $\nMinor = $6 \
    966                      $\nBuild = $7 \
    967                      $\nServicePack = $8 \
    968                      $\nIsServer = $9 \
    969                      $\nExit Code = $ExitCode \
    970                      $\nFirefox Launch Code = $FirefoxLaunchCode \
    971                      $\nDownload Retry Count = $DownloadRetryCount \
    972                      $\nDownloaded Bytes = $DownloadedBytes \
    973                      $\nDownload Size Bytes = $DownloadSizeBytes \
    974                      $\nIntroduction Phase Seconds = $IntroPhaseSeconds \
    975                      $\nOptions Phase Seconds = $OptionsPhaseSeconds \
    976                      $\nDownload Phase Seconds = $0 \
    977                      $\nLast Download Seconds = $1 \
    978                      $\nDownload First Transfer Seconds = $DownloadFirstTransferSeconds \
    979                      $\nPreinstall Phase Seconds = $2 \
    980                      $\nInstall Phase Seconds = $3 \
    981                      $\nFinish Phase Seconds = $4 \
    982                      $\nInitial Install Requirements Code = $InitialInstallRequirementsCode \
    983                      $\nOpened Download Page = $OpenedDownloadPage \
    984                      $\nExisting Profile = $ExistingProfile \
    985                      $\nExisting Version = $ExistingVersion \
    986                      $\nExisting Build ID = $ExistingBuildID \
    987                      $\nNew Version = $R5 \
    988                      $\nNew Build ID = $R6 \
    989                      $\nDefault Install Dir = $R7 \
    990                      $\nHas Admin = $R8 \
    991                      $\nDefault Status = $R2 \
    992                      $\nSet As Sefault Status = $R3 \
    993                      $\nDownload Server IP = $DownloadServerIP \
    994                      $\nPost-Signing Data = $PostSigningData \
    995                      $\nProfile cleanup prompt shown = $ProfileCleanupPromptType \
    996                      $\nDid profile cleanup = $CheckboxCleanupProfile \
    997                      $\nDistribution ID = $DistributionID \
    998                      $\nDistribution Version = $DistributionVersion \
    999                      $\nWindows UBR = $WindowsUBR \
   1000                      $\nStub Installer Build ID = $StubBuildID \
   1001                      $\nLaunched by = $R4"
   1002    ; The following will exit the installer
   1003    SetAutoClose true
   1004    StrCpy $R9 "2"
   1005    Call RelativeGotoPage
   1006 !else
   1007    ${StartTimer} ${DownloadIntervalMS} OnPing
   1008    ; See https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/data/install-ping.html#stub-ping
   1009    ; for instructions on how to make changes to data being reported in this ping
   1010    InetBgDL::Get "${BaseURLStubPing}/${StubURLVersion}${StubURLVersionAppend}/${Channel}/${UpdateChannel}/${AB_CD}/$R0/$R1/$5/$6/$7/$8/$9/$ExitCode/$FirefoxLaunchCode/$DownloadRetryCount/$DownloadedBytes/$DownloadSizeBytes/$IntroPhaseSeconds/$OptionsPhaseSeconds/$0/$1/$DownloadFirstTransferSeconds/$2/$3/$4/$InitialInstallRequirementsCode/$OpenedDownloadPage/$ExistingProfile/$ExistingVersion/$ExistingBuildID/$R5/$R6/$R7/$R8/$R2/$R3/$DownloadServerIP/$PostSigningData/$ProfileCleanupPromptType/$CheckboxCleanupProfile/$DistributionID/$DistributionVersion/$WindowsUBR/$StubBuildID/$R4" \
   1011                  "$PLUGINSDIR\_temp" /END
   1012 !endif
   1013  ${Else}
   1014    ${If} "$IsDownloadFinished" == "false"
   1015      ; Cancel the download in progress
   1016      InetBgDL::Get /RESET /END
   1017    ${EndIf}
   1018    ; The following will exit the installer
   1019    SetAutoClose true
   1020    StrCpy $R9 "2"
   1021    Call RelativeGotoPage
   1022  ${EndIf}
   1023 FunctionEnd
   1024 
   1025 Function OnPing
   1026  InetBgDL::GetStats
   1027  # $0 = HTTP status code, 0=Completed
   1028  # $1 = Completed files
   1029  # $2 = Remaining files
   1030  # $3 = Number of downloaded bytes for the current file
   1031  # $4 = Size of current file (Empty string if the size is unknown)
   1032  # /RESET must be used if status $0 > 299 (e.g. failure)
   1033  # When status is $0 =< 299 it is handled by InetBgDL
   1034  ${If} $2 == 0
   1035  ${OrIf} $0 > 299
   1036    WebBrowser::CancelTimer $TimerHandle
   1037    ${If} $0 > 299
   1038      InetBgDL::Get /RESET /END
   1039    ${EndIf}
   1040    ; The following will exit the installer
   1041    SetAutoClose true
   1042    StrCpy $R9 "2"
   1043    Call RelativeGotoPage
   1044  ${EndIf}
   1045 FunctionEnd
   1046 
   1047 Function CheckInstall
   1048  IntOp $InstallCounterStep $InstallCounterStep + 1
   1049  ${If} $InstallCounterStep >= $InstallTotalSteps
   1050    WebBrowser::CancelTimer $TimerHandle
   1051    ; Close the handle that prevents modification of the full installer
   1052    System::Call 'kernel32::CloseHandle(i $HandleDownload)'
   1053    StrCpy $ExitCode "${ERR_INSTALL_TIMEOUT}"
   1054    ; Use a timer so the UI has a chance to update
   1055    ${StartTimer} ${InstallIntervalMS} DisplayDownloadError
   1056    Return
   1057  ${EndIf}
   1058 
   1059  ${If} $ProgressCompleted < ${PROGRESS_BAR_INSTALL_END_STEP}
   1060    IntOp $0 ${PROGRESS_BAR_INSTALL_END_STEP} - ${PROGRESS_BAR_DOWNLOAD_END_STEP}
   1061    IntOp $0 $InstallCounterStep * $0
   1062    IntOp $0 $0 / $InstallTotalSteps
   1063    IntOp $ProgressCompleted ${PROGRESS_BAR_DOWNLOAD_END_STEP} + $0
   1064    Call SetProgressBars
   1065  ${EndIf}
   1066 
   1067  ${If} ${FileExists} "$INSTDIR\install.log"
   1068    Delete "$INSTDIR\install.tmp"
   1069    CopyFiles /SILENT "$INSTDIR\install.log" "$INSTDIR\install.tmp"
   1070 
   1071    ; The unfocus and refocus that happens approximately here is caused by the
   1072    ; installer calling RefreshShellIcons to refresh the shortcut icons.
   1073 
   1074    ; When the full installer completes the installation the install.log will no
   1075    ; longer be in use.
   1076    ClearErrors
   1077    Delete "$INSTDIR\install.log"
   1078    ${Unless} ${Errors}
   1079      WebBrowser::CancelTimer $TimerHandle
   1080      ; Close the handle that prevents modification of the full installer
   1081      System::Call 'kernel32::CloseHandle(i $HandleDownload)'
   1082      Rename "$INSTDIR\install.tmp" "$INSTDIR\install.log"
   1083      Delete "$PLUGINSDIR\download.exe"
   1084      Delete "$PLUGINSDIR\${CONFIG_INI}"
   1085      System::Call "kernel32::GetTickCount()l .s"
   1086      Pop $EndInstallPhaseTickCount
   1087      Call FinishInstall
   1088    ${EndUnless}
   1089  ${EndIf}
   1090 FunctionEnd
   1091 
   1092 Function FinishInstall
   1093  StrCpy $ProgressCompleted "${PROGRESS_BAR_INSTALL_END_STEP}"
   1094  Call SetProgressBars
   1095 
   1096  ${If} ${FileExists} "$INSTDIR\${FileMainEXE}.moz-upgrade"
   1097    Delete "$INSTDIR\${FileMainEXE}"
   1098    Rename "$INSTDIR\${FileMainEXE}.moz-upgrade" "$INSTDIR\${FileMainEXE}"
   1099  ${EndIf}
   1100 
   1101  StrCpy $ExitCode "${ERR_SUCCESS}"
   1102 
   1103  ${CopyPostSigningData}
   1104  Pop $PostSigningData
   1105 
   1106  Call LaunchApp
   1107 FunctionEnd
   1108 
   1109 Function RelativeGotoPage
   1110  IntCmp $R9 0 0 Move Move
   1111  StrCmp $R9 "X" 0 Move
   1112  StrCpy $R9 "120"
   1113 
   1114  Move:
   1115  SendMessage $HWNDPARENT "0x408" "$R9" ""
   1116 FunctionEnd
   1117 
   1118 Function CheckSpace
   1119  ${If} "$ExistingTopDir" != ""
   1120    StrLen $0 "$ExistingTopDir"
   1121    StrLen $1 "$INSTDIR"
   1122    ${If} $0 <= $1
   1123      StrCpy $2 "$INSTDIR" $3
   1124      ${If} "$2" == "$ExistingTopDir"
   1125        Return
   1126      ${EndIf}
   1127    ${EndIf}
   1128  ${EndIf}
   1129 
   1130  StrCpy $ExistingTopDir "$INSTDIR"
   1131  ${DoUntil} ${FileExists} "$ExistingTopDir"
   1132    ${GetParent} "$ExistingTopDir" $ExistingTopDir
   1133    ${If} "$ExistingTopDir" == ""
   1134      StrCpy $SpaceAvailableBytes "0"
   1135      StrCpy $HasRequiredSpaceAvailable "false"
   1136      Return
   1137    ${EndIf}
   1138  ${Loop}
   1139 
   1140  ${GetLongPath} "$ExistingTopDir" $ExistingTopDir
   1141 
   1142  ; GetDiskFreeSpaceExW requires a backslash.
   1143  StrCpy $0 "$ExistingTopDir" "" -1 ; the last character
   1144  ${If} "$0" != "\"
   1145    StrCpy $0 "\"
   1146  ${Else}
   1147    StrCpy $0 ""
   1148  ${EndIf}
   1149 
   1150  System::Call 'kernel32::GetDiskFreeSpaceExW(w, *l, *l, *l) i("$ExistingTopDir$0", .r1, .r2, .r3) .'
   1151  StrCpy $SpaceAvailableBytes "$1"
   1152 
   1153  System::Int64Op $SpaceAvailableBytes / 1048576
   1154  Pop $1
   1155  System::Int64Op $1 > ${APPROXIMATE_REQUIRED_SPACE_MB}
   1156  Pop $1
   1157  ${If} $1 == 1
   1158    StrCpy $HasRequiredSpaceAvailable "true"
   1159  ${Else}
   1160    StrCpy $HasRequiredSpaceAvailable "false"
   1161  ${EndIf}
   1162 FunctionEnd
   1163 
   1164 
   1165 
   1166 Function LaunchApp
   1167  StrCpy $FirefoxLaunchCode "2"
   1168 
   1169  ; Set the current working directory to the installation directory
   1170  SetOutPath "$INSTDIR"
   1171  ClearErrors
   1172  ${GetParameters} $0
   1173  ${GetOptions} "$0" "/UAC:" $1
   1174  ${If} ${Errors}
   1175    ${If} $CheckboxCleanupProfile == 1
   1176      ${ExecAndWaitForInputIdle} "$\"$INSTDIR\${FileMainEXE}$\" -reset-profile -migration -first-startup"
   1177    ${Else}
   1178      ${ExecAndWaitForInputIdle} "$\"$INSTDIR\${FileMainEXE}$\" -first-startup"
   1179    ${EndIf}
   1180  ${Else}
   1181    StrCpy $R1 $CheckboxCleanupProfile
   1182    GetFunctionAddress $0 LaunchAppFromElevatedProcess
   1183    UAC::ExecCodeSegment $0
   1184  ${EndIf}
   1185 
   1186  StrCpy $AppLaunchWaitTickCount 0
   1187  ${StartTimer} ${AppLaunchWaitIntervalMS} WaitForAppLaunch
   1188 FunctionEnd
   1189 
   1190 Function LaunchAppFromElevatedProcess
   1191  ; Set the current working directory to the installation directory
   1192  SetOutPath "$INSTDIR"
   1193  ${If} $R1 == 1
   1194    ${ExecAndWaitForInputIdle} "$\"$INSTDIR\${FileMainEXE}$\" -reset-profile -migration -first-startup"
   1195  ${Else}
   1196    ${ExecAndWaitForInputIdle} "$\"$INSTDIR\${FileMainEXE}$\" -first-startup"
   1197  ${EndIf}
   1198 FunctionEnd
   1199 
   1200 Function WaitForAppLaunch
   1201  FindWindow $0 "${MainWindowClass}"
   1202  FindWindow $1 "${DialogWindowClass}"
   1203  ${If} $0 <> 0
   1204  ${OrIf} $1 <> 0
   1205    WebBrowser::CancelTimer $TimerHandle
   1206    StrCpy $ProgressCompleted "${PROGRESS_BAR_APP_LAUNCH_END_STEP}"
   1207    Call SetProgressBars
   1208    Call SendPing
   1209    Return
   1210  ${EndIf}
   1211 
   1212  IntOp $AppLaunchWaitTickCount $AppLaunchWaitTickCount + 1
   1213  IntOp $0 $AppLaunchWaitTickCount * ${AppLaunchWaitIntervalMS}
   1214  ${If} $0 >= ${AppLaunchWaitTimeoutMS}
   1215    ; We've waited an unreasonably long time, so just exit.
   1216    WebBrowser::CancelTimer $TimerHandle
   1217    Call SendPing
   1218    Return
   1219  ${EndIf}
   1220 
   1221  ${If} $ProgressCompleted < ${PROGRESS_BAR_APP_LAUNCH_END_STEP}
   1222    IntOp $ProgressCompleted $ProgressCompleted + 1
   1223    Call SetProgressBars
   1224  ${EndIf}
   1225 FunctionEnd
   1226 
   1227 Function DisplayDownloadError
   1228  WebBrowser::CancelTimer $TimerHandle
   1229  ; To better display the error state on the taskbar set the progress completed
   1230  ; value to the total value.
   1231  ${ITBL3SetProgressValue} "100" "100"
   1232  ${ITBL3SetProgressState} "${TBPF_ERROR}"
   1233 
   1234  MessageBox MB_OKCANCEL|MB_ICONSTOP "$(ERROR_DOWNLOAD_CONT2)" IDCANCEL +2 IDOK +1
   1235  Call LaunchHelpPage
   1236  Call SendPing
   1237 FunctionEnd
   1238 
   1239 Function LaunchHelpPage
   1240  StrCpy $OpenedDownloadPage "1" ; Already initialized to 0
   1241  ClearErrors
   1242  ${GetParameters} $0
   1243  ${GetOptions} "$0" "/UAC:" $1
   1244  ${If} ${Errors}
   1245    Call OpenManualDownloadURL
   1246  ${Else}
   1247    GetFunctionAddress $0 OpenManualDownloadURL
   1248    UAC::ExecCodeSegment $0
   1249  ${EndIf}
   1250 FunctionEnd
   1251 
   1252 Function OpenManualDownloadURL
   1253  ClearErrors
   1254  ReadINIStr $0 "${PARTNER_INI}" "DownloadURL" "FallbackPage"
   1255  ${IfNot} ${Errors}
   1256    ExecShell "open" "$0"
   1257  ${Else}
   1258    ExecShell "open" "${URLManualDownload}&installer_arch=$ArchToInstall${URLManualDownloadAppend}"
   1259  ${EndIf}
   1260 FunctionEnd
   1261 
   1262 Function ShouldPromptForProfileCleanup
   1263  ; This will be our return value.
   1264  StrCpy $ProfileCleanupPromptType 0
   1265 
   1266  ; Only consider installations of the same architecture we're installing.
   1267  ${If} $ArchToInstall == ${ARCH_AMD64}
   1268  ${OrIf} $ArchToInstall == ${ARCH_AARCH64}
   1269    SetRegView 64
   1270  ${Else}
   1271    SetRegView 32
   1272  ${EndIf}
   1273 
   1274  ; Make sure $APPDATA is the user's AppData and not ProgramData.
   1275  ; We'll set this back to all at the end of the function.
   1276  SetShellVarContext current
   1277 
   1278  ${FindInstallSpecificProfile}
   1279  Pop $R0
   1280 
   1281  ${If} $R0 == ""
   1282    ; We don't have an install-specific profile, so look for an old-style
   1283    ; default profile instead by checking each numbered Profile section.
   1284    StrCpy $0 0
   1285    ${Do}
   1286      ClearErrors
   1287      ; Check if the section exists by reading a value that must be present.
   1288      ReadINIStr $1 "$APPDATA\Mozilla\Firefox\profiles.ini" "Profile$0" "Path"
   1289      ${If} ${Errors}
   1290        ; We've run out of profile sections.
   1291        ${Break}
   1292      ${EndIf}
   1293 
   1294      ClearErrors
   1295      ReadINIStr $1 "$APPDATA\Mozilla\Firefox\profiles.ini" "Profile$0" "Default"
   1296      ${IfNot} ${Errors}
   1297      ${AndIf} $1 == "1"
   1298        ; We've found the default profile
   1299        ReadINIStr $1 "$APPDATA\Mozilla\Firefox\profiles.ini" "Profile$0" "Path"
   1300        ReadINIStr $2 "$APPDATA\Mozilla\Firefox\profiles.ini" "Profile$0" "IsRelative"
   1301        ${If} $2 == "1"
   1302          StrCpy $R0 "$APPDATA\Mozilla\Firefox\$1"
   1303        ${Else}
   1304          StrCpy $R0 "$1"
   1305        ${EndIf}
   1306        ${Break}
   1307      ${EndIf}
   1308 
   1309      IntOp $0 $0 + 1
   1310    ${Loop}
   1311  ${EndIf}
   1312 
   1313  GetFullPathName $R0 $R0
   1314 
   1315  ${If} $R0 == ""
   1316    ; No profile to clean up, so don't show the cleanup prompt.
   1317    GoTo end
   1318  ${EndIf}
   1319 
   1320  ; We have at least one profile present. If we don't have any installations,
   1321  ; then we need to show the re-install prompt. We'll say there's an
   1322  ; installation present if HKCR\FirefoxURL* exists and points to a real path.
   1323  StrCpy $0 0
   1324  StrCpy $R9 ""
   1325  ${Do}
   1326    ClearErrors
   1327    EnumRegKey $1 HKCR "" $0
   1328    ${If} ${Errors}
   1329    ${OrIf} $1 == ""
   1330      ${Break}
   1331    ${EndIf}
   1332    ${WordFind} "$1" "-" "+1{" $2
   1333    ${If} $2 == "FirefoxURL"
   1334      ClearErrors
   1335      ReadRegStr $2 HKCR "$1\DefaultIcon" ""
   1336      ${IfNot} ${Errors}
   1337        ${GetPathFromString} $2 $1
   1338        ${If} ${FileExists} $1
   1339          StrCpy $R9 $1
   1340          ${Break}
   1341        ${EndIf}
   1342      ${EndIf}
   1343    ${EndIf}
   1344    IntOp $0 $0 + 1
   1345  ${Loop}
   1346  ${If} $R9 == ""
   1347    StrCpy $ProfileCleanupPromptType 1
   1348    GoTo end
   1349  ${EndIf}
   1350 
   1351  ; Okay, there's at least one install, let's see if it's for this channel.
   1352  SetShellVarContext all
   1353  ${GetSingleInstallPath} "Software\Mozilla\${BrandFullNameInternal}" $0
   1354  ${If} $0 == "false"
   1355    SetShellVarContext current
   1356    ${GetSingleInstallPath} "Software\Mozilla\${BrandFullNameInternal}" $0
   1357    ${If} $0 == "false"
   1358      ; Existing installs are not for this channel. Don't show any prompt.
   1359      GoTo end
   1360    ${EndIf}
   1361  ${EndIf}
   1362 
   1363  ; Find out what version the default profile was last used on.
   1364  ${If} ${FileExists} "$R0\compatibility.ini"
   1365    ClearErrors
   1366    ReadINIStr $0 "$R0\compatibility.ini" "Compatibility" "LastVersion"
   1367    ${If} ${Errors}
   1368      GoTo end
   1369    ${EndIf}
   1370    ${WordFind} $0 "." "+1{" $0
   1371 
   1372    ; We don't know what version we're about to install because we haven't
   1373    ; downloaded it yet. Find out what the latest version released on this
   1374    ; channel is and assume we'll be installing that one.
   1375    Call GetLatestReleasedVersion
   1376    ${If} ${Errors}
   1377      ; Use this stub installer's version as a fallback when we can't get the
   1378      ; real current version; this may be behind, but it's better than nothing.
   1379      StrCpy $1 ${AppVersion}
   1380    ${EndIf}
   1381 
   1382    ${WordFind} $1 "." "+1{" $1
   1383    IntOp $1 $1 - 2
   1384 
   1385    ${If} $1 > $0
   1386      ; Default profile was last used more than two versions ago, so we need
   1387      ; to show the paveover version of the profile cleanup prompt.
   1388      StrCpy $ProfileCleanupPromptType 2
   1389    ${EndIf}
   1390  ${EndIf}
   1391 
   1392  end:
   1393  SetRegView lastused
   1394  SetShellVarContext all
   1395 FunctionEnd
   1396 
   1397 Function GetLatestReleasedVersion
   1398  ClearErrors
   1399  Push $0 ; InetBgDl::GetStats uses $0 for the HTTP error code
   1400  ; $1 is our return value, so don't save it
   1401  Push $2 ; InetBgDl::GetStats uses $2 to tell us when the transfer is done
   1402  Push $3 ; $3 - $5 are also set by InetBgDl::GetStats, but we don't use them
   1403  Push $4
   1404  Push $5
   1405  Push $6 ; This is our response timeout counter
   1406 
   1407  InetBgDL::Get /RESET /END
   1408  InetBgDL::Get "https://product-details.mozilla.org/1.0/firefox_versions.json" \
   1409                "$PLUGINSDIR\firefox_versions.json" \
   1410                /CONNECTTIMEOUT 120 /RECEIVETIMEOUT 120 /END
   1411 
   1412  ; Wait for the response, but only give it half a second since this is on the
   1413  ; installer startup path (we haven't even shown a window yet).
   1414  StrCpy $6 0
   1415  ${Do}
   1416    Sleep 100
   1417    InetBgDL::GetStats
   1418    IntOp $6 $6 + 1
   1419 
   1420    ${If} $2 == 0
   1421      ${Break}
   1422    ${ElseIf} $6 >= 5
   1423      InetBgDL::Get /RESET /END
   1424      SetErrors
   1425      GoTo end
   1426    ${EndIf}
   1427  ${Loop}
   1428 
   1429  StrCpy $1 0
   1430  nsJSON::Set /file "$PLUGINSDIR\firefox_versions.json"
   1431  IfErrors end
   1432  ${Select} ${Channel}
   1433  ${Case} "unofficial"
   1434    StrCpy $1 "FIREFOX_NIGHTLY"
   1435  ${Case} "nightly"
   1436    StrCpy $1 "FIREFOX_NIGHTLY"
   1437  ${Case} "aurora"
   1438    StrCpy $1 "FIREFOX_DEVEDITION"
   1439  ${Case} "beta"
   1440    StrCpy $1 "LATEST_FIREFOX_RELEASED_DEVEL_VERSION"
   1441  ${Case} "release"
   1442    StrCpy $1 "LATEST_FIREFOX_VERSION"
   1443  ${EndSelect}
   1444  nsJSON::Get $1 /end
   1445 
   1446  end:
   1447  ${If} ${Errors}
   1448  ${OrIf} $1 == 0
   1449    SetErrors
   1450    StrCpy $1 0
   1451  ${Else}
   1452    Pop $1
   1453  ${EndIf}
   1454 
   1455  Pop $6
   1456  Pop $5
   1457  Pop $4
   1458  Pop $3
   1459  Pop $2
   1460  Pop $0
   1461 FunctionEnd
   1462 
   1463 ; Determine which architecture build we should download and install.
   1464 ; AArch64 is always selected if it's the native architecture of the machine.
   1465 ; Otherwise, we check a few things to determine if AMD64 is appropriate:
   1466 ; 1) Running a 64-bit OS (we've already checked the OS version).
   1467 ; 2) An amount of RAM strictly greater than RAM_NEEDED_FOR_64BIT
   1468 ; 3) No third-party products installed that cause issues with the 64-bit build.
   1469 ;    Currently this includes Lenovo OneKey Theater and Lenovo Energy Management.
   1470 ; We also make sure that the partner.ini file contains a download URL for the
   1471 ; selected architecture, when a partner.ini file eixsts.
   1472 ; If any of those checks fail, the 32-bit x86 build is selected.
   1473 Function GetArchToInstall
   1474  StrCpy $ArchToInstall ${ARCH_X86}
   1475 
   1476  ${If} ${IsNativeARM64}
   1477    StrCpy $ArchToInstall ${ARCH_AARCH64}
   1478    GoTo downloadUrlCheck
   1479  ${EndIf}
   1480 
   1481  ${IfNot} ${IsNativeAMD64}
   1482    Return
   1483  ${EndIf}
   1484 
   1485  System::Call "*(i 64, i, l 0, l, l, l, l, l, l)p.r1"
   1486  System::Call "Kernel32::GlobalMemoryStatusEx(p r1)"
   1487  System::Call "*$1(i, i, l.r2, l, l, l, l, l, l)"
   1488  System::Free $1
   1489  ${If} $2 L<= ${RAM_NEEDED_FOR_64BIT}
   1490    Return
   1491  ${EndIf}
   1492 
   1493  ; Lenovo OneKey Theater can theoretically be in a directory other than this
   1494  ; one, because some installer versions let you change it, but it's unlikely.
   1495  ${If} ${FileExists} "$PROGRAMFILES32\Lenovo\Onekey Theater\windowsapihookdll64.dll"
   1496    Return
   1497  ${EndIf}
   1498 
   1499  ${If} ${FileExists} "$PROGRAMFILES32\Lenovo\Energy Management\Energy Management.exe"
   1500    Return
   1501  ${EndIf}
   1502 
   1503  StrCpy $ArchToInstall ${ARCH_AMD64}
   1504 
   1505  downloadUrlCheck:
   1506  ; If we've selected an architecture that doesn't have a download URL in the
   1507  ; partner.ini, but there is a URL there for 32-bit x86, then fall back to
   1508  ; 32-bit x86 on the theory that we should never use a non-partner build if
   1509  ; we are configured as a partner installer, even if the only build that's
   1510  ; provided is suboptimal for the machine. If there isn't even an x86 URL,
   1511  ; then we won't force x86 and GetDownloadURL will stick with the built-in URL.
   1512  ClearErrors
   1513  ReadINIStr $1 "${PARTNER_INI}" "DownloadURL" "X86"
   1514  ${IfNot} ${Errors}
   1515    ${If} $ArchToInstall == ${ARCH_AMD64}
   1516      ReadINIStr $1 "${PARTNER_INI}" "DownloadURL" "AMD64"
   1517      ${If} ${Errors}
   1518        StrCpy $ArchToInstall ${ARCH_X86}
   1519      ${EndIf}
   1520    ${ElseIf} $ArchToInstall == ${ARCH_AARCH64}
   1521      ReadINIStr $1 "${PARTNER_INI}" "DownloadURL" "AArch64"
   1522      ${If} ${Errors}
   1523        StrCpy $ArchToInstall ${ARCH_X86}
   1524      ${EndIf}
   1525    ${EndIf}
   1526  ${EndIf}
   1527 FunctionEnd
   1528 
   1529 Function GetDownloadURL
   1530  Push $0
   1531  Push $1
   1532 
   1533  ; Start with the appropriate URL from our built-in branding info.
   1534  ${If} $ArchToInstall == ${ARCH_AMD64}
   1535    StrCpy $0 "${URLStubDownloadAMD64}${URLStubDownloadAppend}"
   1536  ${ElseIf} $ArchToInstall == ${ARCH_AARCH64}
   1537    StrCpy $0 "${URLStubDownloadAArch64}${URLStubDownloadAppend}"
   1538  ${Else}
   1539    StrCpy $0 "${URLStubDownloadX86}${URLStubDownloadAppend}"
   1540  ${EndIf}
   1541 
   1542  ; If we have a partner.ini file then use the URL from there instead.
   1543  ClearErrors
   1544  ${If} $ArchToInstall == ${ARCH_AMD64}
   1545    ReadINIStr $1 "${PARTNER_INI}" "DownloadURL" "AMD64"
   1546  ${ElseIf} $ArchToInstall == ${ARCH_AARCH64}
   1547    ReadINIStr $1 "${PARTNER_INI}" "DownloadURL" "AArch64"
   1548  ${Else}
   1549    ReadINIStr $1 "${PARTNER_INI}" "DownloadURL" "X86"
   1550  ${EndIf}
   1551  ${IfNot} ${Errors}
   1552    StrCpy $0 "$1"
   1553  ${EndIf}
   1554 
   1555  Pop $1
   1556  Exch $0
   1557 FunctionEnd
   1558 
   1559 
   1560 Function CommonOnInit
   1561  ; Remove the current exe directory from the search order.
   1562  ; This only effects LoadLibrary calls and not implicitly loaded DLLs.
   1563  System::Call 'kernel32::SetDllDirectoryW(w "")'
   1564  StrCpy $PingAlreadySent "false"
   1565  StrCpy $AbortInstallation "false"
   1566  StrCpy $LANGUAGE 0
   1567  ; This macro is used to set the brand name variables but the ini file method
   1568  ; isn't supported for the stub installer.
   1569  ${SetBrandNameVars} "$PLUGINSDIR\ignored.ini"
   1570 
   1571  StrCpy $CpuSupportsSSE "0"
   1572  Call CheckCpuSupportsSSE
   1573 
   1574  ; Windows 8.1/Server 2012 R2 and lower are not supported.
   1575  ${Unless} ${AtLeastWin10}
   1576    StrCpy $ExitCode "${ERR_PREINSTALL_SYS_OS_REQ}"
   1577    ${If} "$CpuSupportsSSE" == "0"
   1578      strCpy $R7 "$(WARN_MIN_SUPPORTED_OSVER_CPU_MSG2)"
   1579    ${Else}
   1580      strCpy $R7 "$(WARN_MIN_SUPPORTED_OSVER_MSG2)"
   1581    ${EndIf}
   1582    MessageBox MB_OKCANCEL|MB_ICONSTOP "$R7" /SD IDCANCEL IDCANCEL +2
   1583    ExecShell "open" "${URLWinPre10NeedsEsr115}"
   1584    StrCpy $AbortInstallation "true"
   1585    Return
   1586  ${EndUnless}
   1587 
   1588  ; SSE2 CPU support
   1589  ${If} "$CpuSupportsSSE" == "0"
   1590    StrCpy $ExitCode "${ERR_PREINSTALL_SYS_HW_REQ}"
   1591    MessageBox MB_OKCANCEL|MB_ICONSTOP "$(WARN_MIN_SUPPORTED_CPU_MSG2)" /SD IDCANCEL IDCANCEL +2
   1592    ExecShell "open" "${URLSystemRequirements}"
   1593    StrCpy $AbortInstallation "true"
   1594    Return
   1595  ${EndIf}
   1596 
   1597  Call GetArchToInstall
   1598  ${If} $ArchToInstall == ${ARCH_AARCH64}
   1599  ${OrIf} $ArchToInstall == ${ARCH_AMD64}
   1600    StrCpy $INSTDIR "${DefaultInstDir64bit}"
   1601  ${Else}
   1602    StrCpy $INSTDIR "${DefaultInstDir32bit}"
   1603  ${EndIf}
   1604  
   1605  !insertmacro IsTestBreakpointSet ${TestBreakpointArchToInstall}
   1606 
   1607  ; Require elevation if the user can elevate
   1608  ${ElevateUAC}
   1609 
   1610  ; If we have any existing installation, use its location as the default
   1611  ; path for this install, even if it's not the same architecture.
   1612  SetRegView 32
   1613  SetShellVarContext all ; Set SHCTX to HKLM
   1614  ${GetSingleInstallPath} "Software\Mozilla\${BrandFullNameInternal}" $R9
   1615 
   1616  ${If} "$R9" == "false"
   1617    ${If} ${IsNativeAMD64}
   1618    ${OrIf} ${IsNativeARM64}
   1619      SetRegView 64
   1620      ${GetSingleInstallPath} "Software\Mozilla\${BrandFullNameInternal}" $R9
   1621    ${EndIf}
   1622  ${EndIf}
   1623 
   1624  ${If} "$R9" == "false"
   1625    SetShellVarContext current ; Set SHCTX to HKCU
   1626    ${GetSingleInstallPath} "Software\Mozilla\${BrandFullNameInternal}" $R9
   1627  ${EndIf}
   1628 
   1629  StrCpy $PreviousInstallDir ""
   1630  ${If} "$R9" != "false"
   1631    StrCpy $PreviousInstallDir "$R9"
   1632    StrCpy $INSTDIR "$PreviousInstallDir"
   1633  ${EndIf}
   1634 
   1635  ; Used to determine if the default installation directory was used.
   1636  StrCpy $InitialInstallDir "$INSTDIR"
   1637 
   1638 
   1639  ; Initialize the majority of variables except those that need to be reset
   1640  ; when a page is displayed.
   1641  StrCpy $ExitCode "${ERR_UNKNOWN}"
   1642  StrCpy $IntroPhaseSeconds "0"
   1643  StrCpy $OptionsPhaseSeconds "0"
   1644  StrCpy $EndPreInstallPhaseTickCount "0"
   1645  StrCpy $EndInstallPhaseTickCount "0"
   1646  StrCpy $StartDownloadPhaseTickCount "0"
   1647  StrCpy $EndDownloadPhaseTickCount "0"
   1648  StrCpy $InitialInstallRequirementsCode ""
   1649  StrCpy $IsDownloadFinished ""
   1650  StrCpy $FirefoxLaunchCode "0"
   1651  StrCpy $CheckboxShortcuts "1"
   1652  StrCpy $CheckboxCleanupProfile "0"
   1653  StrCpy $ProgressCompleted "0"
   1654 !ifdef MOZ_MAINTENANCE_SERVICE
   1655  ; We can only install the maintenance service if the user is an admin.
   1656  Call IsUserAdmin
   1657  Pop $0
   1658  ${If} "$0" == "true"
   1659    StrCpy $CheckboxInstallMaintSvc "1"
   1660  ${Else}
   1661    StrCpy $CheckboxInstallMaintSvc "0"
   1662  ${EndIf}
   1663 !else
   1664  StrCpy $CheckboxInstallMaintSvc "0"
   1665 !endif
   1666 
   1667 !insertmacro IsTestBreakpointSet ${TestBreakpointMaintService}
   1668 
   1669  StrCpy $FontFamilyName ""
   1670 !ifdef FONT_FILE1
   1671  ${If} ${FileExists} "$FONTS\${FONT_FILE1}"
   1672    StrCpy $FontFamilyName "${FONT_NAME1}"
   1673  ${EndIf}
   1674 !endif
   1675 
   1676 !ifdef FONT_FILE2
   1677  ${If} $FontFamilyName == ""
   1678  ${AndIf} ${FileExists} "$FONTS\${FONT_FILE2}"
   1679    StrCpy $FontFamilyName "${FONT_NAME2}"
   1680  ${EndIf}
   1681 !endif
   1682 
   1683  ${If} $FontFamilyName == ""
   1684    StrCpy $FontFamilyName "$(^Font)"
   1685  ${EndIf}
   1686  
   1687  InitPluginsDir
   1688  File /oname=$PLUGINSDIR\bgstub.jpg "bgstub.jpg"
   1689 
   1690  ; Detect whether the machine is running with a high contrast theme.
   1691  ; We'll hide our background images in that case, both because they don't
   1692  ; always render properly and also to improve the contrast.
   1693  System::Call '*(i 12, i 0, p 0) p . r0'
   1694  ; 0x42 == SPI_GETHIGHCONTRAST
   1695  System::Call 'user32::SystemParametersInfoW(i 0x42, i 0, p r0, i 0)'
   1696  System::Call '*$0(i, i . r1, p)'
   1697  System::Free $0
   1698  IntOp $UsingHighContrastMode $1 & 1
   1699 
   1700  SetShellVarContext all ; Set SHCTX to All Users
   1701  ; If the user doesn't have write access to the installation directory set
   1702  ; the installation directory to a subdirectory of the user's local
   1703  ; application directory (e.g. non-roaming).
   1704  Call CanWrite
   1705  ${If} "$CanWriteToInstallDir" == "false"
   1706    ${GetLocalAppDataFolder} $0
   1707    StrCpy $INSTDIR "$0\${BrandFullName}\"
   1708    Call CanWrite
   1709  ${EndIf}
   1710 
   1711 
   1712  Call CheckSpace
   1713 
   1714  ${If} ${FileExists} "$INSTDIR"
   1715    ; Always display the long path if the path exists.
   1716    ${GetLongPath} "$INSTDIR" $INSTDIR
   1717  ${EndIf}
   1718 
   1719  ; Check whether the install requirements are satisfied using the default
   1720  ; values for metrics.
   1721  ${If} "$InitialInstallRequirementsCode" == ""
   1722    ${If} "$CanWriteToInstallDir" != "true"
   1723    ${AndIf} "$HasRequiredSpaceAvailable" != "true"
   1724      StrCpy $InitialInstallRequirementsCode "1"
   1725    ${ElseIf} "$CanWriteToInstallDir" != "true"
   1726      StrCpy $InitialInstallRequirementsCode "2"
   1727    ${ElseIf} "$HasRequiredSpaceAvailable" != "true"
   1728      StrCpy $InitialInstallRequirementsCode "3"
   1729    ${Else}
   1730      StrCpy $InitialInstallRequirementsCode "0"
   1731    ${EndIf}
   1732  ${EndIf}
   1733 
   1734  Call CanWrite
   1735  ${If} "$CanWriteToInstallDir" == "false"
   1736    StrCpy $ExitCode "${ERR_PREINSTALL_NOT_WRITABLE}"
   1737    MessageBox MB_OK|MB_ICONEXCLAMATION "$(WARN_WRITE_ACCESS_QUIT2)$\n$\n$INSTDIR" /SD IDOK
   1738    StrCpy $AbortInstallation "true"
   1739    Return
   1740  ${EndIf}
   1741 
   1742  !insertmacro IsTestBreakpointSet ${TestBreakpointCanWriteToDir}
   1743 
   1744  Call CheckSpace
   1745  ${If} "$HasRequiredSpaceAvailable" == "false"
   1746      StrCpy $ExitCode "${ERR_PREINSTALL_SPACE}"
   1747    MessageBox MB_OK|MB_ICONEXCLAMATION "$(WARN_DISK_SPACE_QUIT2)"
   1748    StrCpy $AbortInstallation "true"
   1749    Return
   1750  ${EndIf}
   1751 
   1752  !insertmacro IsTestBreakpointSet ${TestBreakpointCheckSpace}
   1753 
   1754  ${InitHashAppModelId} "$INSTDIR" "Software\Mozilla\${AppName}\TaskBarIDs"
   1755 
   1756  File /oname=$PLUGINSDIR\stub_common.css "stub_common.css"
   1757  File /oname=$PLUGINSDIR\stub_common.js "stub_common.js"
   1758 FunctionEnd
   1759 
   1760 ; .onGUIInit isn't needed except for RTL locales
   1761 !ifdef ${AB_CD}_rtl
   1762 Function .onGUIInit
   1763  ${MakeWindowRTL} $HWNDPARENT
   1764 FunctionEnd
   1765 !endif
   1766 
   1767 Function .onGUIEnd
   1768  Delete "$PLUGINSDIR\_temp"
   1769  Delete "$PLUGINSDIR\download.exe"
   1770  Delete "$PLUGINSDIR\${CONFIG_INI}"
   1771 
   1772  ${UnloadUAC}
   1773 FunctionEnd