<?xml version="1.0"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">

  <?define EventSourceName = "chromoting" ?>
  <?define ServiceName = "chromoting" ?>

  <!-- TODO(alexeypa): There strings should be localized,
       see http://crbug.com/121785 -->
  <?if $(var.Branding) ~= Chrome ?>
    <?define ChromotingHost = "Chrome Remote Desktop Host" ?>
    <?define ChromotingServiceName = "Chrome Remote Desktop Service" ?>
    <?define ChromotingServiceDescription = "This service enables incoming connections from Chrome Remote Desktop clients." ?>
    <?define Manufacturer = "Google Inc." ?>
  <?else?>
    <?define ChromotingHost = "Chromoting Host" ?>
    <?define ChromotingServiceName = "Chromoting Service" ?>
    <?define ChromotingServiceDescription = "This service enables incoming connections from Chromoting clients." ?>
    <?define Manufacturer = "The Chromium Authors" ?>
  <?endif?>

  <?define FirewallName = "$(var.ChromotingHost)" ?>

  <?define OmahaAppid = "{b210701e-ffc4-49e3-932b-370728c72662}" ?>
  <?define UpgradeCode = "2b21f767-e157-4fa6-963c-55834c1433a6" ?>

  <?define CoreBinary = "remoting_core.dll" ?>
  <?define HostBinary = "remoting_host.exe" ?>

  <?define ChromotingTypelib = "{b6396c45-b0cc-456b-9f49-f12964ee6df4}" ?>

  <!-- AppIDs used by the COM components. -->
  <?define ControllerAppid = "{4ff35d5e-d226-4550-9248-03e7779e67de}" ?>
  <?define RdpAppid = "{52e6fd1a-f16e-49c0-aacb-5436a915448b}" ?>

  <?define ControllerClass = "ElevatedController Class" ?>
  <?define ControllerProgid =
      "ChromotingElevatedController.ElevatedController" ?>

  <?define IRdpDesktopSessionId = "{6a7699f0-ee43-43e7-aa30-a6738f9bd470}" ?>
  <?define IRdpDesktopSessionEventHandlerId =
      "{b59b96da-83cb-40ee-9b91-c377400fc3e3}" ?>

  <!--
    The long hex value(s) below are security descriptors generated from SDDL
    definition using the PowerShell script below:

    $sddl = "<SDDL definition goes here>"
    $i = ([wmiclass]"Win32_SecurityDescriptorHelper").SDDLToBinarySD($sddl).BinarySD
    -join ($i | foreach {$_.ToString("X2")})
  -->

  <!--
    A security descriptor that gives SYSTEM, built-in administrators and
    LocalService accounts COM_RIGHTS_EXECUTE, COM_RIGHTS_EXECUTE_LOCAL, and
    COM_RIGHTS_ACTIVATE_LOCAL rights. It specifies a mandatory label that
    specifies "no execute up" policy for medium integrity level.

    $sddl = "O:BAG:BAD:(A;;0xb;;;SY)(A;;0xb;;;BA)(A;;0xb;;;LS)S:(ML;;NX;;;ME)"
  -->
  <?define RdpSd = "010014807800000088000000140000003000000002001C000100000011001400040000000101000000000010002000000200480003000000000014000B000000010100000000000512000000000018000B00000001020000000000052000000020020000000014000B0000000101000000000005130000000102000000000005200000002002000001020000000000052000000020020000" ?>

  <!-- Verify that all required parameters are defined. -->
  <?ifndef ControllerClsid ?>
    <?error ControllerClsid must be defined ?>
  <?endif?>

  <?ifndef RdpDesktopSessionClsid ?>
    <?error RdpDesktopSessionClsid must be defined ?>
  <?endif?>

  <?ifndef Version ?>
    <?error Version must be defined ?>
  <?endif?>

  <Product Id="*"
           Language="1033"
           Manufacturer="$(var.Manufacturer)"
           Name="$(var.ChromotingHost)"
           UpgradeCode="$(var.UpgradeCode)"
           Version="$(var.Version)">

    <Package Comments="$(var.ChromotingHost) Package"
             Compressed="yes"
             Description="$(var.ChromotingHost) Package"
             InstallerVersion="200"
             Manufacturer="$(var.Manufacturer)"
             InstallScope="perMachine"/>

    <Condition
      Message="$(var.ChromotingHost) is only supported on Windows XP, Windows Server 2003, or higher.">
      <![CDATA[Installed OR (VersionNT >= 501)]]>
    </Condition>

    <!-- The upgrade rules below could be expressed with MajorUpgrade element.
         Unfortunately, there is a bug in WiX decompiler (Dark) corrupting
         InstallExecuteSequence table. The installation compiled from
         the disassembled .msi schedules RemoveExistingProducts after
         InstallFinalize while the original installation schedules it after
         InstallInitialize. Fortunately, the verbose version of the upgrade
         rules below decompiles correctly, so we use it instead.
         See http://crbug.com/145265 for more details.
    -->
    <Upgrade Id="$(var.UpgradeCode)">
      <UpgradeVersion IncludeMinimum="no"
                      Minimum="$(var.Version)"
                      OnlyDetect="yes"
                      Property="NEWERVERSIONDETECTED" />
      <UpgradeVersion IncludeMaximum="yes"
                      IncludeMinimum="yes"
                      Maximum="$(var.Version)"
                      Minimum="0.0.0.0"
                      Property="OLDERVERSIONBEINGUPGRADED" />
      <!-- Detect versions that didn't handle the usagestats value properly. -->
      <UpgradeVersion IncludeMaximum="yes"
                      IncludeMinimum="yes"
                      Maximum="24.0.1312.29"
                      Minimum="0.0.0.0"
                      Property="BROKENUSAGESTATSVERSION" />
    </Upgrade>

    <Condition Message="A later version of [ProductName] is already installed. Setup will now exit.">
      NOT NEWERVERSIONDETECTED
    </Condition>

    <Media Id="1" Cabinet="chromoting.cab" EmbedCab="yes"/>

    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="ProgramFilesFolder">
        <?if $(var.OfficialBuild) != 0 ?>
          <Directory Id="program_files_google" Name="Google">
            <Directory Id="chromoting" Name="Chrome Remote Desktop">
              <Directory Id="binaries" Name="$(var.Version)"/>
            </Directory>
          </Directory>
        <?else?>
          <Directory Id="chromoting" Name="Chromoting">
            <Directory Id="binaries" Name="$(var.Version)"/>
          </Directory>
        <?endif?>
      </Directory>
      <Directory Id="CommonAppDataFolder">
        <?if $(var.OfficialBuild) != 0 ?>
          <Directory Id="common_app_data_google" Name="Google">
            <Directory Id="config_files" Name="Chrome Remote Desktop"/>
          </Directory>
        <?else?>
          <Directory Id="config_files" Name="Chromoting"/>
        <?endif?>
      </Directory>
    </Directory>

    <DirectoryRef Id="binaries">
      <Component Id="sas" Guid="*">
        <File Id="sas.dll"
              DiskId="1"
              Name="sas.dll"
              Vital="yes"/>
      </Component>

      <Component Id="remoting_core" Guid="*">
        <File Id="$(var.CoreBinary)"
              DiskId="1"
              KeyPath="yes"
              Name="$(var.CoreBinary)"
              Vital="yes"/>

        <util:EventSource xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"
                          Name="$(var.EventSourceName)"
                          Log="Application"
                          CategoryCount="1"
                          CategoryMessageFile="[#$(var.CoreBinary)]"
                          EventMessageFile="[#$(var.CoreBinary)]"
                          SupportsErrors="yes"
                          SupportsInformationals="yes"/>
      </Component>

      <Component Id="remoting_desktop" Guid="*">
        <File Id="remoting_desktop.exe"
              DiskId="1"
              KeyPath="yes"
              Name="remoting_desktop.exe"
              Vital="yes"/>
      </Component>

      <Component Id="remoting_host" Guid="*">
        <File Id="remoting_host.exe"
              DiskId="1"
              Name="remoting_host.exe"
              Vital="yes"/>

        <ServiceInstall Id="install_service"
                        Type="ownProcess"
                        Vital="yes"
                        Name="$(var.ServiceName)"
                        DisplayName="[chromoting_service_display_name]"
                        Description="[chromoting_service_description]"
                        Arguments="--type=daemon --host-config=&quot;[config_files]host.json&quot;"
                        Start="demand"
                        Account="LocalSystem"
                        ErrorControl="ignore"
                        Interactive="no">
          <!-- Configure the service to restart after one minute when it
               crashes.
          -->
          <util:ServiceConfig
              xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"
              FirstFailureActionType="restart"
              ResetPeriodInDays="1"
              RestartServiceDelayInSeconds="60"
              SecondFailureActionType="restart"
              ThirdFailureActionType="restart"/>
        </ServiceInstall>

        <ServiceControl Id="start_service"
                        Stop="both"
                        Remove="uninstall"
                        Name="$(var.ServiceName)"
                        Wait="yes" />

        <fire:FirewallException xmlns:fire="http://schemas.microsoft.com/wix/FirewallExtension"
                                Id="me2me_firewall_exception"
                                IgnoreFailure="yes"
                                Name="$(var.FirewallName)"
                                Profile="all"
                                Program="[#remoting_host.exe]"
                                Scope="any" />
      </Component>

      <?if $(var.OfficialBuild) != 0 ?>
        <Component Id="omaha_registration" Guid="*">
          <RegistryKey Id="omaha_client_key"
                       Root="HKLM"
                       Key="SOFTWARE\Google\Update\Clients\$(var.OmahaAppid)"
                       Action="create">
            <RegistryValue Type="string"
                           Name="pv"
                           Value="$(var.Version)"/>

            <RegistryValue Type="string"
                           Name="name"
                           Value="$(var.ChromotingHost)"/>
          </RegistryKey>
        </Component>
      <?endif?>

      <Component Id="remoting_lib" Guid="*">
        <RegistryKey Root="HKLM"
                     Key="SOFTWARE\Classes">
          <RegistryKey Key="AppId">
            <RegistryKey Key="$(var.ControllerAppid)" Action="create">
              <RegistryValue Type="string"
                             Value="ChromotingElevatedController"/>
            </RegistryKey>

            <RegistryKey Key="$(var.RdpAppid)" Action="create">
              <RegistryValue Type="string"
                             Value="ChromotingRdpDesktopSession"/>
              <RegistryValue Name="AccessPermission"
                             Type="binary"
                             Value="$(var.RdpSd)"/>
              <RegistryValue Name="LaunchPermission"
                             Type="binary"
                             Value="$(var.RdpSd)"/>
              <RegistryValue Name="RunAs"
                             Type="string"
                             Value="NT AUTHORITY\LocalService"/>
            </RegistryKey>

          </RegistryKey>

          <RegistryKey Key="$(var.ControllerProgid)" Action="create">
            <RegistryValue Type="string"
                           Value="$(var.ControllerClass)"/>

            <RegistryKey Key="CLSID" Action="create">
              <RegistryValue Type="string"
                             Value="$(var.ControllerClsid)"/>
            </RegistryKey>

            <RegistryKey Key="CurVer" Action="create">
              <RegistryValue Type="string"
                             Value="$(var.ControllerProgid).$(var.Version)"/>
            </RegistryKey>
          </RegistryKey>

          <RegistryKey Key="$(var.ControllerProgid).$(var.Version)"
                       Action="create">
            <RegistryValue Type="string"
                           Value="$(var.ControllerClass)"/>

            <RegistryKey Key="CLSID" Action="create">
              <RegistryValue Type="string"
                             Value="$(var.ControllerClsid)"/>
            </RegistryKey>
          </RegistryKey>

          <RegistryKey Key="CLSID">
            <RegistryKey Key="$(var.ControllerClsid)" Action="create">
              <RegistryValue Type="string"
                             Value="$(var.ControllerClass)"/>

              <RegistryValue Type="string"
                             Name="AppID"
                             Value="$(var.ControllerAppid)"/>

              <RegistryValue Type="string"
                             Name="LocalizedString"
                             Value="@[binaries]$(var.CoreBinary),-103"/>

              <RegistryKey Key="LocalServer32" Action="create">
                <RegistryValue Type="string"
                               Value="[binaries]$(var.HostBinary) --type=controller"/>
              </RegistryKey>

              <RegistryKey Key="ProgID" Action="create">
                <RegistryValue Type="string"
                               Value="$(var.ControllerProgid).$(var.Version)"/>
              </RegistryKey>

              <RegistryKey Key="TypeLib" Action="create">
                <RegistryValue Type="string"
                               Value="$(var.ChromotingTypelib)"/>
              </RegistryKey>

              <RegistryKey Key="VersionIndependentProgID" Action="create">
                <RegistryValue Type="string"
                               Value="$(var.ControllerProgid)"/>
              </RegistryKey>

              <RegistryKey Key="Elevation" Action="create">
                <RegistryValue Type="integer"
                               Name="Enabled"
                               Value="1"/>
                <RegistryValue Type="string"
                               Name="IconReference"
                               Value="@[binaries]$(var.CoreBinary),-104"/>
              </RegistryKey>
            </RegistryKey>
            <RegistryKey Key="$(var.RdpDesktopSessionClsid)" Action="create">
              <RegistryValue Type="string"
                             Value="RdpDesktopSession Class"/>

              <RegistryValue Type="string"
                             Name="AppID"
                             Value="$(var.RdpAppid)"/>

              <RegistryKey Key="LocalServer32" Action="create">
                <RegistryValue Type="string"
                               Value="[binaries]$(var.HostBinary) --type=rdp_desktop_session"/>
              </RegistryKey>

              <RegistryKey Key="TypeLib" Action="create">
                <RegistryValue Type="string"
                               Value="$(var.ChromotingTypelib)"/>
              </RegistryKey>
            </RegistryKey>

            <!-- IRdpDesktopSession PSFactory -->
            <RegistryKey Key="$(var.IRdpDesktopSessionId)"
                         Action="create">
              <RegistryValue Type="string"
                             Value="IRdpDesktopSession PSFactory"/>

              <RegistryKey Key="InprocServer32" Action="create">
                <RegistryValue Type="string"
                               Value="[binaries]$(var.CoreBinary)"/>
              </RegistryKey>
            </RegistryKey>

            <!-- IRdpDesktopSessionEventHandler PSFactory -->
            <RegistryKey Key="$(var.IRdpDesktopSessionEventHandlerId)"
                         Action="create">
              <RegistryValue Type="string"
                             Value="IRdpDesktopSessionEventHandler PSFactory"/>

              <RegistryKey Key="InprocServer32" Action="create">
                <RegistryValue Type="string"
                               Value="[binaries]$(var.CoreBinary)"/>
              </RegistryKey>
            </RegistryKey>
          </RegistryKey>

          <RegistryKey Key="Interface">
            <!-- IDaemonControl2 interface -->
            <RegistryKey Key="{655bd819-c08c-4b04-80c2-f160739ff6ef}"
                         Action="create">
              <RegistryKey Key="ProxyStubClsid32" Action="create">
                <RegistryValue Type="string"
                               Value="{00020424-0000-0000-C000-000000000046}"/>
              </RegistryKey>

              <RegistryKey Key="TypeLib" Action="create">
                <RegistryValue Type="string"
                               Value="$(var.ChromotingTypelib)"/>
              </RegistryKey>
            </RegistryKey>

            <!-- IDaemonControl interface -->
            <RegistryKey Key="{e051a481-6345-4ba1-bdb1-cf7929955268}"
                         Action="create">
              <RegistryKey Key="ProxyStubClsid32" Action="create">
                <RegistryValue Type="string"
                               Value="{00020424-0000-0000-C000-000000000046}"/>
              </RegistryKey>

              <RegistryKey Key="TypeLib" Action="create">
                <RegistryValue Type="string"
                               Value="$(var.ChromotingTypelib)"/>
              </RegistryKey>
            </RegistryKey>

            <!-- IRdpDesktopSession interface -->
            <RegistryKey Key="$(var.IRdpDesktopSessionId)"
                         Action="create">
              <RegistryValue Type="string"
                             Value="IRdpDesktopSession"/>
              <RegistryKey Key="ProxyStubClsid32" Action="create">
                <RegistryValue Type="string"
                               Value="$(var.IRdpDesktopSessionId)"/>
              </RegistryKey>
            </RegistryKey>

            <!-- IRdpDesktopSessionEventHandler interface -->
            <RegistryKey Key="$(var.IRdpDesktopSessionEventHandlerId)"
                         Action="create">
              <RegistryValue Type="string"
                             Value="IRdpDesktopSessionEventHandler"/>
              <RegistryKey Key="ProxyStubClsid32" Action="create">
                <RegistryValue Type="string"
                               Value="$(var.IRdpDesktopSessionEventHandlerId)"/>
              </RegistryKey>

              <RegistryKey Key="TypeLib" Action="create">
                <RegistryValue Type="string"
                               Value="$(var.ChromotingTypelib)"/>
              </RegistryKey>
            </RegistryKey>
          </RegistryKey>

          <RegistryKey Key="Typelib">
            <RegistryKey Key="$(var.ChromotingTypelib)" Action="create">
              <RegistryKey Key="1.0" Action="create">
                <RegistryValue Type="string"
                               Value="Chromoting 1.0 Type Library"/>
                <RegistryKey Key="0" Action="create">
                  <RegistryKey Key="win32" Action="create">
                    <RegistryValue Type="string"
                                   Value="[binaries]$(var.CoreBinary)"/>
                  </RegistryKey>
                </RegistryKey>

                <RegistryKey Key="FLAGS" Action="create">
                  <RegistryValue Type="string"
                                 Value="0"/>
                </RegistryKey>

                <RegistryKey Key="HELPDIR" Action="create">
                  <RegistryValue Type="string"
                                 Value="[binaries]"/>
                </RegistryKey>
              </RegistryKey>
            </RegistryKey>
          </RegistryKey>
        </RegistryKey>

      </Component>

      <!-- Register with Sawbuck. See http://code.google.com/p/sawbuck/. -->
      <Component Id="sawbuck_provider" Guid="*">
        <RegistryKey Root="HKLM"
                     Key="SOFTWARE\Google\Sawbuck\Providers">
          <RegistryKey Key="{2db51ca1-4fd8-4b88-b5a2-fb8606b66b02}"
                       Action="create">
            <RegistryValue Type="string" Value="Chromoting"/>
            <RegistryValue Name="default_flags" Type="integer" Value="1"/>
            <RegistryValue Name="default_level" Type="integer" Value="4"/>
            <RegistryKey Key="Flags" Action="create">
              <RegistryKey Key="Stack Trace" Action="create">
                <RegistryValue Type="integer" Value="1"/>
              </RegistryKey>
              <RegistryKey Key="Text Only" Action="create">
                <RegistryValue Type="integer" Value="2"/>
              </RegistryKey>
            </RegistryKey>
          </RegistryKey>
        </RegistryKey>
      </Component>

      <!-- Delete the usagestats flag to reset the crash dump reporting settings
           for existing users. -->
      <Component Id="delete_usagestats"
                 Guid="5c73f2b9-b865-426f-81cc-90a27ebb54aa"
                 KeyPath="yes">
        <Condition>BROKENUSAGESTATSVERSION</Condition>
        <RemoveRegistryValue
            Id="usagestats"
            Key="SOFTWARE\Google\Update\ClientStateMedium\$(var.OmahaAppid)"
            Name="usagestats"
            Root="HKLM" />
      </Component>

    </DirectoryRef>

    <DirectoryRef Id="config_files">
      <!-- Delete debug.log from previous versions -->
      <Component Id="delete_debug_log"
                 Guid="b309082a-e6fa-4dc7-98e4-3d83c896561d">
        <RemoveFile Id="debug.log"
                    Name="debug.log"
                    On="both" />
      </Component>
    </DirectoryRef>

    <!-- The service is always installed in the stopped state with start type
         set to 'manual'. This becomes a problem when upgrading an existing
         installation that is configured to start the service automatically.

         Here we check the startup type before making any changes, then restart
         the service and change its startup type as needed once the installation
         is finished. -->
    <Property Id="CHROMOTING_SERVICE_START_TYPE">
      <RegistrySearch Id="chromoting_service_start_type"
                      Root="HKLM"
                      Key="SYSTEM\CurrentControlSet\services\$(var.ServiceName)"
                      Name="Start"
                      Type="raw" />
    </Property>

    <CustomAction Id="query_auto_start_service"
                  Property="auto_start_service"
                  Value="[CHROMOTING_SERVICE_START_TYPE]" />

    <CustomAction Id="set_auto_start_service"
                  Impersonate="no"
                  Execute="deferred"
                  Script="jscript">
      <![CDATA[
        var controller = new ActiveXObject("$(var.ControllerProgid)");
        controller.StartDaemon();
      ]]>
    </CustomAction>

    <CustomAction Id="set_service_display_name"
                  Property="chromoting_service_display_name"
                  Value="@[binaries]$(var.CoreBinary),-101" />
    <CustomAction Id="set_service_description"
                  Property="chromoting_service_description"
                  Value="@[binaries]$(var.CoreBinary),-102" />

    <!-- XP does not support MUI strings in the service name and description, so
         we fall back to plain strings on XP. -->
    <CustomAction Id="set_service_display_name_xp"
                  Property="chromoting_service_display_name"
                  Value="$(var.ChromotingServiceName)" />
    <CustomAction Id="set_service_description_xp"
                  Property="chromoting_service_description"
                  Value="$(var.ChromotingServiceDescription)" />

    <UIRef Id="WixUI_ErrorProgressText" />

    <Feature Id="chromoting_host" Level="1" Title="$(var.ChromotingHost)">
      <ComponentRef Id="delete_debug_log"/>
      <ComponentRef Id="delete_usagestats"/>
      <?if $(var.OfficialBuild) != 0 ?>
        <ComponentRef Id="omaha_registration"/>
      <?endif?>
      <ComponentRef Id="remoting_core"/>
      <ComponentRef Id="remoting_desktop"/>
      <ComponentRef Id="remoting_host"/>
      <ComponentRef Id="remoting_lib"/>
      <ComponentRef Id="sas"/>
      <ComponentRef Id="sawbuck_provider"/>
    </Feature>

    <!-- Set the icon shown in Add/Remove Programs. -->
    <Icon Id="chromoting.ico" SourceFile="chromoting.ico"/>
    <Property Id="ARPPRODUCTICON" Value="chromoting.ico" />

    <InstallExecuteSequence>
      <Custom Action="query_auto_start_service" Before="InstallInitialize"/>
      <Custom Action="set_auto_start_service" After="StartServices">
        <![CDATA[NOT REMOVE AND (auto_start_service = "#2")]]>
      </Custom>

      <!-- Set the serivce name and description -->
      <Custom Action="set_service_display_name_xp" Before="InstallInitialize">
        <![CDATA[VersionNT < 600]]>
      </Custom>
      <Custom Action="set_service_description_xp" Before="InstallInitialize">
        <![CDATA[VersionNT < 600]]>
      </Custom>
      <Custom Action="set_service_display_name" Before="InstallInitialize">
        <![CDATA[VersionNT >= 600]]>
      </Custom>
      <Custom Action="set_service_description" Before="InstallInitialize">
        <![CDATA[VersionNT >= 600]]>
      </Custom>

      <!-- Schedule RemoveExistingProducts before installing any files.
           See http://msdn.microsoft.com/en-us/library/aa371197.aspx. -->
      <RemoveExistingProducts After="InstallInitialize" />
    </InstallExecuteSequence>
  </Product>
</Wix>