diff --git a/.github/actions/package/action.yml b/.github/actions/package/action.yml index 950b9cb8e27..c753cc054d5 100644 --- a/.github/actions/package/action.yml +++ b/.github/actions/package/action.yml @@ -45,6 +45,12 @@ runs: using: composite steps: + - name: Parse distrib name + id: parse-distrib + uses: ./.github/actions/parse-distrib + with: + distrib: ${{ inputs.distrib }} + - name: Import gpg key env: RPM_GPG_SIGNING_KEY: ${{ inputs.rpm_gpg_key }} @@ -62,14 +68,10 @@ runs: export ARCH="${{ inputs.arch }}" if [ "${{ inputs.package_extension }}" = "rpm" ]; then - export DIST=".${{ inputs.distrib }}" + export DIST="${{ steps.parse-distrib.outputs.package_distrib_separator }}${{ steps.parse-distrib.outputs.package_distrib_name }}" else export DIST="" - if [ "${{ inputs.stability }}" = "unstable" ] || [ "${{ inputs.stability }}" = "canary" ]; then - export RELEASE="$RELEASE~${{ inputs.distrib }}" - else - export RELEASE="1~${{ inputs.distrib }}" - fi + export RELEASE="$RELEASE${{ steps.parse-distrib.outputs.package_distrib_separator }}${{ steps.parse-distrib.outputs.package_distrib_name }}" fi MAJOR_LEFT=$( echo $MAJOR_VERSION | cut -d "." -f1 ) diff --git a/.github/actions/parse-distrib/action.yml b/.github/actions/parse-distrib/action.yml new file mode 100644 index 00000000000..39888187619 --- /dev/null +++ b/.github/actions/parse-distrib/action.yml @@ -0,0 +1,45 @@ +name: "parse-distrib" +description: "parse distrib name." +inputs: + distrib: + description: "The distribution name" + required: true +outputs: + package_distrib_separator: + description: "Separator between package version and distrib number" + value: ${{ steps.parse-distrib.outputs.package_distrib_separator }} + package_distrib_name: + description: "Distribution suffix in package name" + value: ${{ steps.parse-distrib.outputs.package_distrib_name }} + +runs: + using: "composite" + steps: + - name: Parse distrib + id: parse-distrib + run: | + if [[ "${{ inputs.distrib }}" == "centos7" || "${{ inputs.distrib }}" == "el7" ]]; then + PACKAGE_DISTRIB_SEPARATOR="." + PACKAGE_DISTRIB_NAME="el7" + elif [[ "${{ inputs.distrib }}" == "alma8" || "${{ inputs.distrib }}" == "el8" ]]; then + PACKAGE_DISTRIB_SEPARATOR="." + PACKAGE_DISTRIB_NAME="el8" + elif [[ "${{ inputs.distrib }}" == "alma9" || "${{ inputs.distrib }}" == "el9" ]]; then + PACKAGE_DISTRIB_SEPARATOR="." + PACKAGE_DISTRIB_NAME="el9" + elif [[ "${{ inputs.distrib }}" == "bullseye" ]]; then + PACKAGE_DISTRIB_SEPARATOR="+" + PACKAGE_DISTRIB_NAME="deb11u1" + elif [[ "${{ inputs.distrib }}" == "bookworm" ]]; then + PACKAGE_DISTRIB_SEPARATOR="+" + PACKAGE_DISTRIB_NAME="deb12u1" + elif [[ "${{ inputs.distrib }}" == "jammy" ]]; then + PACKAGE_DISTRIB_SEPARATOR="-" + PACKAGE_DISTRIB_NAME="0ubuntu.22.04" + else + echo "::error::Distrib ${{ inputs.distrib }} cannot be parsed" + exit 1 + fi + echo "package_distrib_separator=$PACKAGE_DISTRIB_SEPARATOR" >> $GITHUB_OUTPUT + echo "package_distrib_name=$PACKAGE_DISTRIB_NAME" >> $GITHUB_OUTPUT + shell: bash diff --git a/.github/actions/promote-to-stable/action.yml b/.github/actions/promote-to-stable/action.yml index a031cc74d82..e450b3c4b90 100644 --- a/.github/actions/promote-to-stable/action.yml +++ b/.github/actions/promote-to-stable/action.yml @@ -34,6 +34,12 @@ runs: JF_URL: https://centreon.jfrog.io JF_ACCESS_TOKEN: ${{ inputs.artifactory_token }} + - name: Parse distrib name + id: parse-distrib + uses: ./.github/actions/parse-distrib + with: + distrib: ${{ inputs.distrib }} + - name: Promote RPM packages to stable if: ${{ startsWith(inputs.distrib, 'el') }} run: | @@ -81,7 +87,7 @@ runs: # Build target path based on ARCH echo "[DEBUG] - Build $ARCH target path." - TARGET_PATH="$ROOT_REPO_PATH/${{ inputs.major_version }}/${{ inputs.distrib }}/${{ inputs.stability }}/$ARCH/RPMS/${{ inputs.module_name }}/" + TARGET_PATH="$ROOT_REPO_PATH/${{ inputs.major_version }}/${{ inputs.distrib }}/stable/$ARCH/RPMS/${{ inputs.module_name }}/" echo "[DEBUG] - Target path: $TARGET_PATH" # Download candidates for promote @@ -91,10 +97,15 @@ runs: jf rt download $ARTIFACT --flat done + DRY_RUN_FLAG="--dry-run" + if [ "${{ inputs.stability }}" == "stable" ]; then + DRY_RUN_FLAG="" + fi + # Upload previously downloaded candidates to TARGET_PATH for ARTIFACT_DL in $(dir|grep -E "*.rpm"); do echo "[DEBUG] - Promoting (upload) $ARTIFACT_DL to stable $TARGET_PATH." - jf rt upload "$ARTIFACT_DL" "$TARGET_PATH" --flat + jf rt upload "$ARTIFACT_DL" "$TARGET_PATH" --flat $DRY_RUN_FLAG done # Cleanup before next round of candidates @@ -104,7 +115,7 @@ runs: shell: bash - name: Promote DEB packages to stable - if: ${{ !inputs.release_cloud && contains(fromJSON('["bullseye", "bookworm"]'), inputs.distrib) }} + if: ${{ contains(fromJSON('["bullseye", "bookworm"]'), inputs.distrib) }} run: | set -eux @@ -123,7 +134,7 @@ runs: SRC_PATHS=$(jf rt search --include-dirs $ROOT_REPO_PATH-testing/pool/${{ inputs.module_name }}/*.deb | jq -r '.[].path') ;; *) - SRC_PATHS=$(jf rt search --include-dirs $ROOT_REPO_PATH-testing/pool/${{ inputs.module_name }}/*${{ inputs.distrib }}*.deb | jq -r '.[].path') + SRC_PATHS=$(jf rt search --include-dirs $ROOT_REPO_PATH-testing/pool/${{ inputs.module_name }}/*${{ steps.parse-distrib.outputs.package_distrib_name }}*.deb | jq -r '.[].path') ;; esac @@ -132,12 +143,12 @@ runs: echo "[DEBUG] - Source path found: $SRC_PATH" done else - echo "[DEBUG] - No source path found." - continue + echo "::warning::No source path found." + exit 0 fi echo "[DEBUG] - Build target path." - TARGET_PATH="$ROOT_REPO_PATH-${{ inputs.stability }}/pool/${{ inputs.module_name }}/" + TARGET_PATH="$ROOT_REPO_PATH-stable/pool/${{ inputs.module_name }}/" echo "[DEBUG] - Target path: $TARGET_PATH" echo "[DEBUG] - Promoting DEB testing artifacts to stable." @@ -151,16 +162,20 @@ runs: ARTIFACT_SEARCH_PATTERN=".+\.deb" ;; *) - ARTIFACT_SEARCH_PATTERN=".+${{ inputs.distrib }}.+\.deb" + ARTIFACT_SEARCH_PATTERN=".+${{ steps.parse-distrib.outputs.package_distrib_name }}.+\.deb" ;; esac + DRY_RUN_FLAG="--dry-run" + if [ "${{ inputs.stability }}" == "stable" ]; then + DRY_RUN_FLAG="" + fi + for ARTIFACT_DL in $(dir -1|grep -E $ARTIFACT_SEARCH_PATTERN); do ARCH=$(echo $ARTIFACT_DL | cut -d '_' -f3 | cut -d '.' -f1) echo "[DEBUG] - Promoting (upload) $ARTIFACT_DL to stable $TARGET_PATH." - jf rt upload "$ARTIFACT_DL" "$TARGET_PATH" --deb "${{ inputs.distrib }}/main/$ARCH" --flat + jf rt upload "$ARTIFACT_DL" "$TARGET_PATH" --deb "${{ inputs.distrib }}/main/$ARCH" --flat $DRY_RUN_FLAG done rm -f *.deb - shell: bash diff --git a/.github/docker/Dockerfile.gorgone-testing-alma8 b/.github/docker/Dockerfile.gorgone-testing-alma8 index 7fe2db43131..be82a09bc17 100644 --- a/.github/docker/Dockerfile.gorgone-testing-alma8 +++ b/.github/docker/Dockerfile.gorgone-testing-alma8 @@ -1,12 +1,27 @@ -FROM almalinux:8 +ARG REGISTRY_URL=docker.io +ARG VERSION -RUN bash -e < /dev/null 2>&1 + +apt-get update -wget -O- https://apt-key.centreon.com | gpg --dearmor | tee /etc/apt/trusted.gpg.d/centreon.gpg > /dev/null 2>&1 apt-get clean rm -rf /var/lib/apt/lists/* diff --git a/.github/docker/Dockerfile.gorgone-testing-bullseye b/.github/docker/Dockerfile.gorgone-testing-bullseye deleted file mode 100644 index 0c3cc92a2a8..00000000000 --- a/.github/docker/Dockerfile.gorgone-testing-bullseye +++ /dev/null @@ -1,28 +0,0 @@ -FROM debian:bullseye - -ENV DEBIAN_FRONTEND noninteractive -# fix locale -ENV LANG en_US.utf8 - -RUN bash -e < /dev/null 2>&1 -apt-get clean -rm -rf /var/lib/apt/lists/* - -EOF diff --git a/.github/docker/Dockerfile.gorgone-testing-jammy b/.github/docker/Dockerfile.gorgone-testing-jammy deleted file mode 100644 index 6338489114d..00000000000 --- a/.github/docker/Dockerfile.gorgone-testing-jammy +++ /dev/null @@ -1,41 +0,0 @@ -FROM ubuntu:jammy - -ENV DEBIAN_FRONTEND=noninteractive - -# Set locale -RUN apt-get update && \ - apt-get install -y locales libcurl4-openssl-dev curl wget zstd jq lsb-release mariadb-client iproute2 && \ - apt-get install -y ca-certificates apt-transport-https software-properties-common gnupg2 procps lsof && \ - localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8 - -ENV LANG=en_US.UTF-8 - -# Add Centreon repositories and their public key -RUN echo "deb https://packages.centreon.com/ubuntu-standard-24.05-testing/ jammy main" | tee -a /etc/apt/sources.list.d/centreon-testing.list && \ - echo "deb https://packages.centreon.com/ubuntu-plugins-testing/ jammy main" | tee -a /etc/apt/sources.list.d/centreon-plugins-testing.list && \ - wget -O- https://apt-key.centreon.com | gpg --dearmor | tee /etc/apt/trusted.gpg.d/centreon.gpg > /dev/null 2>&1 && \ - apt-get update - -# Install required packages and Robotframework -RUN apt-get update && \ - apt-get install -y \ - python3 \ - python3-dev \ - python3-pip \ - python3-venv - -# Create a virtual environment and install Robot Framework -RUN python3 -m venv /opt/robotframework-env && \ - /opt/robotframework-env/bin/pip install --no-cache-dir \ - robotframework \ - robotframework-examples \ - robotframework-databaselibrary \ - robotframework-requests \ - robotframework-jsonlibrary \ - pymysql - -# Clean up -RUN apt-get clean && rm -rf /var/lib/apt/lists/* - -# Set the PATH to include the virtual environment -ENV PATH="/opt/robotframework-env/bin:$PATH" diff --git a/.github/scripts/agent_installer_test.ps1 b/.github/scripts/agent_installer_test.ps1 new file mode 100644 index 00000000000..8de2f10c333 --- /dev/null +++ b/.github/scripts/agent_installer_test.ps1 @@ -0,0 +1,267 @@ +# +# Copyright 2024 Centreon +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# +# For more information : contact@centreon.com +# + +# This script test CMA installer in silent mode + + +function test_args_to_registry { +<# +.SYNOPSIS + start a program and check values in registry + +.PARAMETER exe_path + path of the installer to execute + +.PARAMETER exe_args + installer arguments + +.PARAMETER expected_registry_values + hash_table as @{'host'='host_1';'endpoint'='127.0.0.1'} +#> + param ( + [string] $exe_path, + [string[]] $exe_args, + $expected_registry_values + ) + + Write-Host "arguments: $exe_args" + + $process_info= Start-Process -PassThru $exe_path $exe_args + Wait-Process -Id $process_info.Id + if ($process_info.ExitCode -ne 0) { + Write-Host "fail to execute $exe_path with arguments $exe_args" + Write-Host "exit status = " $process_info.ExitCode + exit 1 + } + + foreach ($value_name in $expected_registry_values.Keys) { + $expected_value = $($expected_registry_values[$value_name]) + $real_value = (Get-ItemProperty -Path HKLM:\Software\Centreon\CentreonMonitoringAgent -Name $value_name).$value_name + if ($expected_value -ne $real_value) { + Write-Host "unexpected value for $value_name, expected: $expected_value, read: $real_value" + exit 1 + } + } +} + +Write-Host "############################ all install uninstall ############################" + +$args = '/S','--install_cma', '--install_plugins', '--hostname', "my_host_name_1", "--endpoint","127.0.0.1:4317" +$expected = @{ 'endpoint'='127.0.0.1:4317';'host'='my_host_name_1';'log_type'='EventLog'; 'log_level' = 'error'; 'encryption' = 0;'reversed_grpc_streaming'= 0 } +test_args_to_registry "agent/installer/centreon-monitoring-agent.exe" $args $expected + +if (!(Get-ItemProperty -Path HKLM:\Software\Centreon\CentreonMonitoringAgent)) { + Write-Host "no registry entry created" + exit 1 +} + +Get-Process | Select-Object -Property ProcessName | Select-String centagent + +$info = Get-Process | Select-Object -Property ProcessName | Select-String centagent + +#$info = Get-Process centagent 2>$null +if (!$info) { + Write-Host "centagent.exe not started" + exit 1 +} + +if (![System.Io.File]::Exists("C:\Program Files\Centreon\Plugins\centreon_plugins.exe")) { + Write-Host "centreon_plugins.exe not installed" + exit 1 +} + +$process_info= Start-Process -PassThru "C:\Program Files\Centreon\CentreonMonitoringAgent\uninstall.exe" "/S", "--uninstall_cma","--uninstall_plugins" +Wait-Process -Id $process_info.Id +if ($process_info.ExitCode -ne 0) { + Write-Host "bad uninstaller exit code" + exit 1 +} + +Start-Sleep -Seconds 5 + +Get-Process | Select-Object -Property ProcessName | Select-String centagent + +$info = Get-Process | Select-Object -Property ProcessName | Select-String centagent +#$info = Get-Process centagent 2>$null +if ($info) { + Write-Host "centagent.exe running" + exit 1 +} + +if ([System.Io.File]::Exists("C:\Program Files\Centreon\Plugins\centreon_plugins.exe")) { + Write-Host "centreon_plugins.exe not removed" + exit 1 +} + +Write-Host "The followind command will output errors, don't take it into account" +#the only mean I have found to test key erasure under CI +#Test-Path doesn't work +$key_found = true +try { + Get-ChildItem -Path HKLM:\Software\Centreon\CentreonMonitoringAgent +} +catch { + $key_found = false +} + +if ($key_found) { + Write-Host "registry entry not removed" + exit 1 +} + + +Write-Host "############################ installer test ############################" + +$process_info= Start-Process -PassThru "agent/installer/centreon-monitoring-agent.exe" "/S", "--help" +Wait-Process -Id $process_info.Id +if ($process_info.ExitCode -ne 2) { + Write-Host "bad --help exit code" + exit 1 +} + +$process_info= Start-Process -PassThru "agent/installer/centreon-monitoring-agent.exe" "/S", "--version" +Wait-Process -Id $process_info.Id +if ($process_info.ExitCode -ne 2) { + Write-Host "bad --version exit code" + exit 1 +} + +#missing mandatory parameters +$process_info= Start-Process -PassThru "agent/installer/centreon-monitoring-agent.exe" "/S", "--install_cma" +Wait-Process -Id $process_info.Id +if ($process_info.ExitCode -ne 1) { + Write-Host "bad no parameter exit code " $process_info.ExitCode + exit 1 +} + +$process_info= Start-Process -PassThru "agent/installer/centreon-monitoring-agent.exe" "/S", "--install_cma","--hostname","toto" +Wait-Process -Id $process_info.Id +if ($process_info.ExitCode -ne 1) { + Write-Host "bad no endpoint exit code " $process_info.ExitCode + exit 1 +} + +$process_info= Start-Process -PassThru "agent/installer/centreon-monitoring-agent.exe" "/S", "--install_cma","--hostname","toto","--endpoint","turlututu" +Wait-Process -Id $process_info.Id +if ($process_info.ExitCode -ne 1) { + Write-Host "bad wrong endpoint exit code " $process_info.ExitCode + exit 1 +} + +$process_info= Start-Process -PassThru "agent/installer/centreon-monitoring-agent.exe" "/S", "--install_cma","--hostname","toto","--endpoint","127.0.0.1:4317","--log_type","file" +Wait-Process -Id $process_info.Id +if ($process_info.ExitCode -ne 1) { + Write-Host "bad no log file path " $process_info.ExitCode + exit 1 +} + +$process_info= Start-Process -PassThru "agent/installer/centreon-monitoring-agent.exe" "/S", "--install_cma","--hostname","toto","--endpoint","127.0.0.1:4317","--log_type","file","--log_file","C:" +Wait-Process -Id $process_info.Id +if ($process_info.ExitCode -ne 1) { + Write-Host "bad log file path " $process_info.ExitCode + exit 1 +} + +$process_info= Start-Process -PassThru "agent/installer/centreon-monitoring-agent.exe" "/S", "--install_cma","--hostname","toto","--endpoint","127.0.0.1:4317","--log_level","dsfsfd" +Wait-Process -Id $process_info.Id +if ($process_info.ExitCode -ne 1) { + Write-Host "bad log level " $process_info.ExitCode + exit 1 +} + +$process_info= Start-Process -PassThru "agent/installer/centreon-monitoring-agent.exe" "/S", "--install_cma","--hostname","toto","--endpoint","127.0.0.1:4317","--reverse","--log_type","file","--log_file","C:\Users\Public\cma.log","--encryption" +Wait-Process -Id $process_info.Id +if ($process_info.ExitCode -ne 1) { + Write-Host "reverse mode, encryption and no private_key " $process_info.ExitCode + exit 1 +} + +$process_info= Start-Process -PassThru "agent/installer/centreon-monitoring-agent.exe" "/S", "--install_cma","--hostname","toto","--endpoint","127.0.0.1:4317","--reverse","--log_type","file","--log_file","C:\Users\Public\cma.log","--encryption","--private_key","C:" +Wait-Process -Id $process_info.Id +if ($process_info.ExitCode -ne 1) { + Write-Host "reverse mode, encryption and bad private_key path" $process_info.ExitCode + exit 1 +} + +$process_info= Start-Process -PassThru "agent/installer/centreon-monitoring-agent.exe" "/S", "--install_cma","--hostname","toto","--endpoint","127.0.0.1:4317","--reverse","--log_type","file","--log_file","C:\Users\Public\cma.log","--encryption","--private_key","C:\Users\Public\private_key.key" +Wait-Process -Id $process_info.Id +if ($process_info.ExitCode -ne 1) { + Write-Host "reverse mode, encryption and no certificate" $process_info.ExitCode + exit 1 +} + +$process_info= Start-Process -PassThru "agent/installer/centreon-monitoring-agent.exe" "/S", "--install_cma","--hostname","toto","--endpoint","127.0.0.1:4317","--reverse","--log_type","file","--log_file","C:\Users\Public\cma.log","--encryption","--private_key","C:\Users\Public\private_key.key", "--public_cert", "C:" +Wait-Process -Id $process_info.Id +if ($process_info.ExitCode -ne 1) { + Write-Host "reverse mode, encryption and bad certificate path" $process_info.ExitCode + exit 1 +} + + +$args = '/S','--install_cma','--hostname', "my_host_name_1", "--endpoint","127.0.0.1:4317" +$expected = @{ 'endpoint'='127.0.0.1:4317';'host'='my_host_name_1';'log_type'='EventLog'; 'log_level' = 'error'; 'encryption' = 0;'reversed_grpc_streaming'= 0 } +test_args_to_registry "agent/installer/centreon-monitoring-agent.exe" $args $expected + +$args = '/S','--install_cma','--hostname', "my_host_name_2", "--endpoint","127.0.0.2:4317", "--log_type", "file", "--log_file", "C:\Users\Public\cma.log", "--log_level", "trace", "--log_max_file_size", "15", "--log_max_files", "10" +$expected = @{ 'endpoint'='127.0.0.2:4317';'host'='my_host_name_2';'log_type'='File'; 'log_level' = 'trace'; 'log_file'='C:\Users\Public\cma.log'; 'encryption' = 0;'reversed_grpc_streaming'= 0; 'log_max_file_size' = 15; 'log_max_files' = 10; } +test_args_to_registry "agent/installer/centreon-monitoring-agent.exe" $args $expected + +$args = '/S','--install_cma','--hostname', "my_host_name_2", "--endpoint","127.0.0.3:4317", "--log_type", "file", "--log_file", "C:\Users\Public\cma.log", "--log_level", "trace", "--encryption" +$expected = @{ 'endpoint'='127.0.0.3:4317';'host'='my_host_name_2';'log_type'='File'; 'log_level' = 'trace'; 'log_file'='C:\Users\Public\cma.log'; 'encryption' = 1;'reversed_grpc_streaming'= 0 } +test_args_to_registry "agent/installer/centreon-monitoring-agent.exe" $args $expected + +$args = '/S','--install_cma','--hostname', "my_host_name_2", "--endpoint","127.0.0.4:4317", "--log_type", "file", "--log_file", "C:\Users\Public\cma.log", "--log_level", "trace", "--encryption", "--private_key", "C:\Users crypto\private.key", "--public_cert", "D:\tutu\titi.crt", "--ca", "C:\Users\Public\ca.crt", "--ca_name", "tls_ca_name" +$expected = @{ 'endpoint'='127.0.0.4:4317';'host'='my_host_name_2';'log_type'='File'; 'log_level' = 'trace'; 'log_file'='C:\Users\Public\cma.log'; 'encryption' = 1;'reversed_grpc_streaming'= 0; 'certificate'='D:\tutu\titi.crt'; 'private_key'='C:\Users crypto\private.key'; 'ca_certificate' = 'C:\Users\Public\ca.crt'; 'ca_name' = 'tls_ca_name' } +test_args_to_registry "agent/installer/centreon-monitoring-agent.exe" $args $expected + +$args = '/S','--install_cma','--hostname', "my_host_name_2", "--endpoint","127.0.0.5:4317", "--log_type", "file", "--log_file", "C:\Users\Public\cma_rev.log", "--log_level", "trace", "--encryption", "--reverse", "--private_key", "C:\Users crypto\private_rev.key", "--public_cert", "D:\tutu\titi_rev.crt", "--ca", "C:\Users\Public\ca_rev.crt", "--ca_name", "tls_ca_name_rev" +$expected = @{ 'endpoint'='127.0.0.5:4317';'host'='my_host_name_2';'log_type'='File'; 'log_level' = 'trace'; 'log_file'='C:\Users\Public\cma_rev.log'; 'encryption' = 1;'reversed_grpc_streaming'= 1; 'certificate'='D:\tutu\titi_rev.crt'; 'private_key'='C:\Users crypto\private_rev.key'; 'ca_certificate' = 'C:\Users\Public\ca_rev.crt'; 'ca_name' = 'tls_ca_name_rev' } +test_args_to_registry "agent/installer/centreon-monitoring-agent.exe" $args $expected + + +Write-Host "############################ modifier test ############################" + +$args = '/S','--hostname', "my_host_name_10", "--endpoint","127.0.0.10:4317", "--no_reverse" +$expected = @{ 'endpoint'='127.0.0.10:4317';'host'='my_host_name_10';'log_type'='File'; 'log_level' = 'trace'; 'log_file'='C:\Users\Public\cma_rev.log'; 'encryption' = 1;'reversed_grpc_streaming'= 0; 'certificate'='D:\tutu\titi_rev.crt'; 'private_key'='C:\Users crypto\private_rev.key'; 'ca_certificate' = 'C:\Users\Public\ca_rev.crt'; 'ca_name' = 'tls_ca_name_rev' } +test_args_to_registry "agent/installer/centreon-monitoring-agent-modify.exe" $args $expected + +$args = '/S',"--log_type", "file", "--log_file", "C:\Users\Public\cma_rev2.log", "--log_level", "debug", "--log_max_file_size", "50", "--log_max_files", "20" +$expected = @{ 'endpoint'='127.0.0.10:4317';'host'='my_host_name_10';'log_type'='File'; 'log_level' = 'debug'; 'log_file'='C:\Users\Public\cma_rev2.log'; 'encryption' = 1;'reversed_grpc_streaming'= 0; 'certificate'='D:\tutu\titi_rev.crt'; 'log_max_file_size' = 50; 'log_max_files' = 20;'private_key'='C:\Users crypto\private_rev.key'; 'ca_certificate' = 'C:\Users\Public\ca_rev.crt'; 'ca_name' = 'tls_ca_name_rev' } +test_args_to_registry "agent/installer/centreon-monitoring-agent-modify.exe" $args $expected + +$args = '/S',"--log_type", "EventLog", "--log_level", "error" +$expected = @{ 'endpoint'='127.0.0.10:4317';'host'='my_host_name_10';'log_type'='event-log'; 'log_level' = 'error'; 'encryption' = 1;'reversed_grpc_streaming'= 0; 'certificate'='D:\tutu\titi_rev.crt'; 'private_key'='C:\Users crypto\private_rev.key'; 'ca_certificate' = 'C:\Users\Public\ca_rev.crt'; 'ca_name' = 'tls_ca_name_rev' } +test_args_to_registry "agent/installer/centreon-monitoring-agent-modify.exe" $args $expected + +$args = '/S',"--private_key", "C:\Users crypto\private_rev2.key", "--public_cert", "D:\tutu\titi_rev2.crt" +$expected = @{ 'endpoint'='127.0.0.10:4317';'host'='my_host_name_10';'log_type'='event-log'; 'log_level' = 'error'; 'encryption' = 1;'reversed_grpc_streaming'= 0; 'certificate'='D:\tutu\titi_rev2.crt'; 'private_key'='C:\Users crypto\private_rev2.key'; 'ca_certificate' = 'C:\Users\Public\ca_rev.crt'; 'ca_name' = 'tls_ca_name_rev' } +test_args_to_registry "agent/installer/centreon-monitoring-agent-modify.exe" $args $expected + +$args = '/S',"--ca", "C:\Users\Public\ca_rev2.crt", "--ca_name", "tls_ca_name_rev2" +$expected = @{ 'endpoint'='127.0.0.10:4317';'host'='my_host_name_10';'log_type'='event-log'; 'log_level' = 'error'; 'encryption' = 1;'reversed_grpc_streaming'= 0; 'certificate'='D:\tutu\titi_rev2.crt'; 'private_key'='C:\Users crypto\private_rev2.key'; 'ca_certificate' = 'C:\Users\Public\ca_rev2.crt'; 'ca_name' = 'tls_ca_name_rev2' } +test_args_to_registry "agent/installer/centreon-monitoring-agent-modify.exe" $args $expected + +$args = '/S',"--no_encryption" +$expected = @{ 'endpoint'='127.0.0.10:4317';'host'='my_host_name_10';'log_type'='event-log'; 'log_level' = 'error'; 'encryption' = 0;'reversed_grpc_streaming'= 0; 'certificate'='D:\tutu\titi_rev2.crt'; 'private_key'='C:\Users crypto\private_rev2.key'; 'ca_certificate' = 'C:\Users\Public\ca_rev2.crt'; 'ca_name' = 'tls_ca_name_rev2' } +test_args_to_registry "agent/installer/centreon-monitoring-agent-modify.exe" $args $expected + + + +Write-Host "############################ end test ############################" + +exit 0 diff --git a/.github/scripts/agent_robot_test.ps1 b/.github/scripts/agent_robot_test.ps1 new file mode 100644 index 00000000000..37345457f0a --- /dev/null +++ b/.github/scripts/agent_robot_test.ps1 @@ -0,0 +1,111 @@ +# +# Copyright 2024 Centreon +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# +# For more information : contact@centreon.com +# + +# This script test windows CMA +# We first start four instances of centreon agent (reverse or not, encryption or not) +# Then, we install collect in a wsl and start robot test on it. +# Used ports are: +# - 4317 no reversed, no encryption +# - 4318 no reversed, encryption +# - 4320 reversed, no encryption +# - 4321 reversed, encryption +# All files are shared between wsl and windows, we translate it with $wsl_path +# By this share, we use certificates (server.*) on both world +# In order to communicate bteween two worlds, we use hostname and IP of the host +# That's why we rewrite /etc/hosts on wsl side +# agent logs are saved in reports and wsl fail tests are saved in it also in case of failure + + +Write-Host "Work in" $pwd.ToString() + +$current_dir = (pwd).Path +$wsl_path = "/mnt/" + $current_dir.SubString(0,1).ToLower() + "/" + $current_dir.SubString(3).replace('\','/') + +mkdir reports + +reg import agent/conf/centagent.reg + +Set-ItemProperty -Path HKLM:\SOFTWARE\Centreon\CentreonMonitoringAgent -Name log_type -Value file +Set-ItemProperty -Path HKLM:\SOFTWARE\Centreon\CentreonMonitoringAgent -Name host -Value host_1 +Set-ItemProperty -Path HKLM:\SOFTWARE\Centreon\CentreonMonitoringAgent -Name log_level -Value trace + + +#in wsl1, no VM, so IP address are identical in host and wsl +#windows can connect to linux on localhost but linux must use host ip +$my_host_name = $env:COMPUTERNAME +$my_ip = (Get-NetIpAddress -AddressFamily IPv4 | Where-Object IPAddress -ne "127.0.0.1" | SELECT IPAddress -First 1).IPAddress +$pwsh_path = (get-command pwsh.exe).Path + +# generate certificate used by wsl and windows +openssl req -new -newkey rsa:2048 -days 365 -nodes -x509 -keyout server_grpc.key -out server_grpc.crt -subj "/CN=${my_host_name}" + +Set-ItemProperty -Path HKLM:\SOFTWARE\Centreon\CentreonMonitoringAgent -Name endpoint -Value ${my_host_name}:4317 +Set-ItemProperty -Path HKLM:\SOFTWARE\Centreon\CentreonMonitoringAgent -Name reversed_grpc_streaming -Value 0 +$agent_log_path = $current_dir + "\reports\centagent.log" +Set-ItemProperty -Path HKLM:\SOFTWARE\Centreon\CentreonMonitoringAgent -Name log_file -Value $agent_log_path + +#Start agent +$agent_process = Start-Process -PassThru -FilePath build_windows\agent\Release\centagent.exe -ArgumentList "--standalone" -RedirectStandardOutput reports\centagent_stdout.log -RedirectStandardError reports\centagent_stderr.log + +Write-Host ($agent_process | Format-Table | Out-String) + +Start-Sleep -Seconds 1 + +#encrypted version +Set-ItemProperty -Path HKLM:\SOFTWARE\Centreon\CentreonMonitoringAgent -Name ca_certificate -Value ${current_dir}/server_grpc.crt +Set-ItemProperty -Path HKLM:\SOFTWARE\Centreon\CentreonMonitoringAgent -Name endpoint -Value ${my_host_name}:4318 +Set-ItemProperty -Path HKLM:\SOFTWARE\Centreon\CentreonMonitoringAgent -Name encryption -Value 1 +$agent_log_path = $current_dir + "\reports\encrypted_centagent.log" +Set-ItemProperty -Path HKLM:\SOFTWARE\Centreon\CentreonMonitoringAgent -Name log_file -Value $agent_log_path + +Start-Process -FilePath build_windows\agent\Release\centagent.exe -ArgumentList "--standalone" -RedirectStandardOutput reports\encrypted_centagent_stdout.log -RedirectStandardError reports\encrypted_centagent_stderr.log + + +Start-Sleep -Seconds 1 + +#Start reverse agent +Set-ItemProperty -Path HKLM:\SOFTWARE\Centreon\CentreonMonitoringAgent -Name ca_certificate -Value "" +Set-ItemProperty -Path HKLM:\SOFTWARE\Centreon\CentreonMonitoringAgent -Name encryption -Value 0 +Set-ItemProperty -Path HKLM:\SOFTWARE\Centreon\CentreonMonitoringAgent -Name endpoint -Value 0.0.0.0:4320 +Set-ItemProperty -Path HKLM:\SOFTWARE\Centreon\CentreonMonitoringAgent -Name reverse_connection -Value 1 +$agent_log_path = $current_dir + "\reports\reverse_centagent.log" +Set-ItemProperty -Path HKLM:\SOFTWARE\Centreon\CentreonMonitoringAgent -Name log_file -Value $agent_log_path + +Start-Process -FilePath build_windows\agent\Release\centagent.exe -ArgumentList "--standalone" -RedirectStandardOutput reports\reversed_centagent_stdout.log -RedirectStandardError reports\reversed_centagent_stderr.log + +Start-Sleep -Seconds 1 + +#reversed and encrypted +Set-ItemProperty -Path HKLM:\SOFTWARE\Centreon\CentreonMonitoringAgent -Name private_key -Value ${current_dir}/server_grpc.key +Set-ItemProperty -Path HKLM:\SOFTWARE\Centreon\CentreonMonitoringAgent -Name public_cert -Value ${current_dir}/server_grpc.crt +Set-ItemProperty -Path HKLM:\SOFTWARE\Centreon\CentreonMonitoringAgent -Name encryption -Value 1 +Set-ItemProperty -Path HKLM:\SOFTWARE\Centreon\CentreonMonitoringAgent -Name endpoint -Value 0.0.0.0:4321 +$agent_log_path = $current_dir + "\reports\encrypted_reverse_centagent.log" +Set-ItemProperty -Path HKLM:\SOFTWARE\Centreon\CentreonMonitoringAgent -Name log_file -Value $agent_log_path + +Start-Process -FilePath build_windows\agent\Release\centagent.exe -ArgumentList "--standalone" -RedirectStandardOutput reports\encrypted_reversed_centagent_stdout.log -RedirectStandardError reports\encrypted_reversed_centagent_stderr.log + +wsl cd $wsl_path `&`& .github/scripts/wsl-collect-test-robot.sh broker-engine/cma.robot $my_host_name $my_ip $pwsh_path ${current_dir}.replace('\','/') + +#something wrong in robot test => exit 1 => failure +if (Test-Path -Path 'reports\windows-cma-failed' -PathType Container) { + exit 1 +} + + + diff --git a/.github/scripts/collect-prepare-test-robot.sh b/.github/scripts/collect-prepare-test-robot.sh index c3cbc047175..7c8e1c603df 100755 --- a/.github/scripts/collect-prepare-test-robot.sh +++ b/.github/scripts/collect-prepare-test-robot.sh @@ -16,47 +16,7 @@ ssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -P "" << /dev/null 2>&1 & - else - mkdir -p /run/mysqld - chown mysql:mysql /run/mysqld - mariadbd --socket=/run/mysqld/mysqld.sock --user=root > /dev/null 2>&1 & - fi - sleep 5 - - echo "########################### Init centreon database ############################" - - mysql -e "CREATE USER IF NOT EXISTS 'centreon'@'localhost' IDENTIFIED BY 'centreon'" - mysql -e "CREATE USER IF NOT EXISTS 'root_centreon'@'localhost' IDENTIFIED BY 'centreon'" -fi - -mysql -e "GRANT SELECT,UPDATE,DELETE,INSERT,CREATE,DROP,INDEX,ALTER,LOCK TABLES,CREATE TEMPORARY TABLES, EVENT,CREATE VIEW ON *.* TO 'centreon'@'localhost'" -mysql -e "GRANT ALL PRIVILEGES ON *.* TO 'root_centreon'@'localhost'" - -cat resources/centreon.sql | sed "s/DBNameConf/centreon/g" > /tmp/centreon.sql - -mysql -u root_centreon -pcentreon < resources/centreon_storage.sql -mysql -u root_centreon -pcentreon < /tmp/centreon.sql +.github/scripts/collect-setup-database.sh $database_type if [ $database_type == 'mysql' ]; then killall -w mysqldtoto diff --git a/.github/scripts/collect-setup-database.sh b/.github/scripts/collect-setup-database.sh new file mode 100755 index 00000000000..636c54290e4 --- /dev/null +++ b/.github/scripts/collect-setup-database.sh @@ -0,0 +1,53 @@ +#!/bin/bash +set -e +set -x + + +database_type=$1 + +. /etc/os-release +distrib=${ID} +distrib=$(echo $distrib | tr '[:lower:]' '[:upper:]') + + +if [ $database_type == 'mysql' ]; then + echo "########################### Start MySQL ######################################" + #workaround of forbidden execution of mysqld + cp /usr/libexec/mysqld /usr/libexec/mysqldtoto + /usr/libexec/mysqldtoto --user=root --initialize-insecure + /usr/libexec/mysqldtoto --user=root & + + while [ ! -S /var/lib/mysql/mysql.sock ] && [ ! -S /var/run/mysqld/mysqld.sock ]; do + sleep 10 + done + +else + echo "########################### Start MariaDB ######################################" + if [ "$distrib" = "ALMALINUX" ]; then + mysql_install_db --user=root --basedir=/usr --datadir=/var/lib/mysql + mariadbd --socket=/var/lib/mysql/mysql.sock --user=root > /dev/null 2>&1 & + else + mkdir -p /run/mysqld + chown mysql:mysql /run/mysqld + mariadbd --socket=/run/mysqld/mysqld.sock --user=root > /dev/null 2>&1 & + fi +fi + +sleep 5 +echo "########################### Init centreon database ############################" + +mysql -e "CREATE USER IF NOT EXISTS 'centreon'@'localhost' IDENTIFIED BY 'centreon'" +mysql -e "CREATE USER IF NOT EXISTS 'root_centreon'@'localhost' IDENTIFIED BY 'centreon'" + + +mysql -e "GRANT SELECT,UPDATE,DELETE,INSERT,CREATE,DROP,INDEX,ALTER,LOCK TABLES,CREATE TEMPORARY TABLES, EVENT,CREATE VIEW ON *.* TO 'centreon'@'localhost'" +mysql -e "GRANT ALL PRIVILEGES ON *.* TO 'root_centreon'@'localhost'" + +cat resources/centreon.sql | sed "s/DBNameConf/centreon/g" > /tmp/centreon.sql + +echo "create storage database" +mysql -u root_centreon -pcentreon < resources/centreon_storage.sql + +echo "create conf database" +mysql -u root_centreon -pcentreon < /tmp/centreon.sql + diff --git a/.github/scripts/windows-agent-compile.ps1 b/.github/scripts/windows-agent-compile.ps1 index 831cf31f363..b3246b59ed3 100644 --- a/.github/scripts/windows-agent-compile.ps1 +++ b/.github/scripts/windows-agent-compile.ps1 @@ -24,6 +24,14 @@ Write-Host $env:VCPKG_BINARY_SOURCES $current_dir = $pwd.ToString() +#install recent version of 7zip needed by some packages +Write-Host "install 7zip" + +#download 7zip +Invoke-WebRequest -Uri "https://www.7-zip.org/a/7z2408-x64.msi" -OutFile "7z2408-x64.msi" +#install 7zip +Start-Process 'msiexec.exe' -ArgumentList '/I "7z2408-x64.msi" /qn' -Wait + #get cache from s3 $files_to_hash = "vcpkg.json", "custom-triplets\x64-windows.cmake", "CMakeLists.txt", "CMakeListsWindows.txt" $files_content = Get-Content -Path $files_to_hash -Raw @@ -32,12 +40,13 @@ $writer = [System.IO.StreamWriter]::new($stringAsStream) $writer.write($files_content -join " ") $writer.Flush() $stringAsStream.Position = 0 +$vcpkg_release = "2024.10.21" $vcpkg_hash = Get-FileHash -InputStream $stringAsStream -Algorithm SHA256 | Select-Object Hash -$file_name = "windows-agent-vcpkg-dependencies-cache-" + $vcpkg_hash.Hash +$file_name = "windows-agent-vcpkg-dependencies-cache-" + $vcpkg_hash.Hash + "-" + $vcpkg_release $file_name_extension = "${file_name}.7z" #try to get compiled dependenciesfrom s3 -Write-Host "try to download compiled dependencies from s3: $file_name_extension $file_name_extension" +Write-Host "try to download compiled dependencies from s3: $file_name_extension" aws --quiet s3 cp s3://centreon-collect-robot-report/$file_name_extension $file_name_extension if ( $? -ne $true ) { #no => generate @@ -46,7 +55,7 @@ if ( $? -ne $true ) { Write-Host "#######################################################################################################################" Write-Host "install vcpkg" - git clone --depth 1 -b 2024.07.12 https://github.com/microsoft/vcpkg.git + git clone --depth 1 -b $vcpkg_release https://github.com/microsoft/vcpkg.git cd vcpkg bootstrap-vcpkg.bat cd $current_dir @@ -57,22 +66,24 @@ if ( $? -ne $true ) { Write-Host "compile vcpkg dependencies" vcpkg install --vcpkg-root $env:VCPKG_ROOT --x-install-root build_windows\vcpkg_installed --x-manifest-root . --overlay-triplets custom-triplets --triplet x64-windows - Write-Host "Compress binary archive" - 7z a $file_name_extension build_windows\vcpkg_installed - Write-Host "Upload binary archive" - aws s3 cp $file_name_extension s3://centreon-collect-robot-report/$file_name_extension - Write-Host "create CMake files" + if ( $? -eq $true ) { + Write-Host "Compress binary archive" + 7z a $file_name_extension build_windows\vcpkg_installed + Write-Host "Upload binary archive" + aws s3 cp $file_name_extension s3://centreon-collect-robot-report/$file_name_extension + } } else { 7z x $file_name_extension Write-Host "Create cmake files from binary-cache downloaded without use vcpkg" } - +Write-Host "create CMake files" cmake -DCMAKE_BUILD_TYPE=Release -DWITH_TESTING=On -DWINDOWS=On -DBUILD_FROM_CACHE=On -S. -DVCPKG_CRT_LINKAGE=dynamic -DBUILD_SHARED_LIBS=OFF -Bbuild_windows -Write-Host "build agent and tests" + +Write-Host "------------- build agent only ---------------" cmake --build build_windows --config Release diff --git a/.github/scripts/wsl-collect-test-robot.sh b/.github/scripts/wsl-collect-test-robot.sh new file mode 100755 index 00000000000..ba54ad04fb0 --- /dev/null +++ b/.github/scripts/wsl-collect-test-robot.sh @@ -0,0 +1,35 @@ +#!/bin/bash +set -x + +test_file=$1 + +export RUN_ENV=WSL +export HOST_NAME=$2 +export USED_ADDRESS=$3 +export PWSH_PATH=$4 +export WINDOWS_PROJECT_PATH=$5 + + +#in order to connect to windows we neeed to use windows ip +echo "127.0.0.1 localhost" > /etc/hosts +echo "${USED_ADDRESS} ${HOST_NAME}" >> /etc/hosts + +echo "##### /etc/hosts: ######" +cat /etc/hosts + +echo "##### Starting tests #####" +cd tests +./init-proto.sh + +echo "####################### Run Centreon Collect Robot Tests #######################" + +robot $test_file + +echo "####################### End of Centreon Collect Robot Tests #######################" + +if [ -d failed ] ; then + echo "failure save logs in ${PWD}/../reports" + cp -rp failed ../reports/windows-cma-failed + cp log.html ../reports/windows-cma-log.html + cp output.xml ../reports/windows-cma-output.xml +fi diff --git a/.github/workflows/centreon-collect.yml b/.github/workflows/centreon-collect.yml index 464198dea2a..d59282d0fe9 100644 --- a/.github/workflows/centreon-collect.yml +++ b/.github/workflows/centreon-collect.yml @@ -18,6 +18,22 @@ on: required: true default: false type: boolean + legacy_engine: + description: 'Compile Engine with legacy configuration library' + required: true + default: true + type: boolean + packages_in_artifact: + description: 'Save packages in artifacts' + required: true + default: false + type: boolean + unit_tests: + description: 'Execute the unit tests' + required: true + default: true + type: boolean + schedule: - cron: '30 0 * * 1-5' pull_request: @@ -110,12 +126,12 @@ jobs: unit-test: needs: [get-version] - if: ${{ ! contains(fromJson('["stable"]'), needs.get-version.outputs.stability) }} + if: ${{ github.event.inputs.unit_tests == 'true' && ! contains(fromJson('["stable"]'), needs.get-version.outputs.stability) }} strategy: fail-fast: false matrix: - distrib: [alma8, alma9, debian-bullseye, debian-bookworm] + distrib: [alma8, alma9, debian-bookworm] runs-on: [self-hosted, collect] @@ -125,6 +141,7 @@ jobs: SCCACHE_REGION: "eu-west-1" AWS_ACCESS_KEY_ID: ${{ secrets.COLLECT_S3_ACCESS_KEY }} AWS_SECRET_ACCESS_KEY: ${{ secrets.COLLECT_S3_SECRET_KEY }} + LEGACY_ENGINE: ${{ github.event.inputs.legacy_engine != 'false' && 'ON' || 'OFF' }} container: image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/centreon-collect-${{ matrix.distrib }}:${{ needs.get-version.outputs.img_version }} @@ -195,7 +212,7 @@ jobs: -DWITH_MODULE_SIMU=On \ -DCMAKE_C_COMPILER_LAUNCHER=${SCCACHE_PATH} \ -DCMAKE_CXX_COMPILER_LAUNCHER=${SCCACHE_PATH} \ - -DLEGACY_ENGINE=ON \ + -DLEGACY_ENGINE=${LEGACY_ENGINE} \ -S . ninja -Cbuild @@ -224,7 +241,38 @@ jobs: package: needs: [get-version] if: ${{ ! contains(fromJson('["stable"]'), needs.get-version.outputs.stability) }} + strategy: + fail-fast: false + matrix: + include: + - image: centreon-collect-alma8 + distrib: el8 + package_extension: rpm + runner: collect + arch: amd64 + - image: centreon-collect-alma9 + distrib: el9 + package_extension: rpm + runner: collect + arch: amd64 + - image: centreon-collect-debian-bookworm + distrib: bookworm + package_extension: deb + runner: collect + arch: amd64 + - image: centreon-collect-ubuntu-jammy + distrib: jammy + package_extension: deb + runner: collect + arch: amd64 + - image: centreon-collect-debian-bookworm-arm64 + distrib: bookworm + package_extension: deb + runner: collect-arm64 + arch: arm64 + uses: ./.github/workflows/package-collect.yml + with: major_version: ${{ needs.get-version.outputs.major_version }} minor_version: ${{ needs.get-version.outputs.minor_version }} @@ -232,6 +280,13 @@ jobs: release: ${{ needs.get-version.outputs.release }} commit_hash: ${{ github.sha }} stability: ${{ needs.get-version.outputs.stability }} + legacy_engine: ${{ github.event.inputs.legacy_engine != 'false' && 'ON' || 'OFF' }} + packages_in_artifact: ${{ github.event.inputs.packages_in_artifact == 'true' }} + image: ${{ matrix.image }} + distrib: ${{ matrix.distrib }} + package_extension: ${{ matrix.package_extension }} + runner: ${{ matrix.runner }} + arch: ${{ matrix.arch }} secrets: inherit robot-test: @@ -260,13 +315,6 @@ jobs: database_type: mysql test_group_name: robot_test-mysql-el9-amd64 tests_params: '{}' - - distrib: bullseye - image: centreon-collect-debian-bullseye-arm64-test - package_extension: deb - arch: arm64 - database_type: mariadb - test_group_name: robot_test-mariadb-bullseye-arm64 - tests_params: '{}' - distrib: bookworm image: centreon-collect-debian-bookworm-arm64-test package_extension: deb @@ -384,14 +432,8 @@ jobs: strategy: matrix: include: - - distrib: bullseye - arch: amd64 - - distrib: bullseye - arch: arm64 - distrib: bookworm arch: amd64 - - distrib: jammy - arch: amd64 name: deliver ${{ matrix.distrib }} @@ -412,17 +454,16 @@ jobs: release_cloud: ${{ needs.get-version.outputs.release_cloud }} promote: - needs: [get-version] + needs: [get-version, deliver-rpm, deliver-deb] if: | - github.event_name != 'workflow_dispatch' && - contains(fromJson('["stable"]'), needs.get-version.outputs.stability) && + (contains(fromJson('["stable", "testing"]'), needs.get-version.outputs.stability) && github.event_name != 'workflow_dispatch') && ! cancelled() && ! contains(needs.*.result, 'failure') && ! contains(needs.*.result, 'cancelled') runs-on: [self-hosted, common] strategy: matrix: - distrib: [el8, el9, bullseye, bookworm, jammy] + distrib: [el8, el9, bookworm] steps: - name: Checkout sources diff --git a/.github/workflows/check-status.yml b/.github/workflows/check-status.yml index 6cfbf4f7884..cd7a383daef 100644 --- a/.github/workflows/check-status.yml +++ b/.github/workflows/check-status.yml @@ -47,7 +47,7 @@ jobs: const result = await github.rest.checks.listSuitesForRef({ owner: context.repo.owner, repo: context.repo.repo, - ref: "${{ github.event.pull_request.head.sha }}" + ref: "${{ github.head_ref }}" }); result.data.check_suites.forEach(({ app: { slug }, conclusion, id}) => { if (slug === 'github-actions') { diff --git a/.github/workflows/docker-builder.yml b/.github/workflows/docker-builder.yml index 2db215693b4..469b29e404d 100644 --- a/.github/workflows/docker-builder.yml +++ b/.github/workflows/docker-builder.yml @@ -98,8 +98,8 @@ jobs: uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 with: registry: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }} - username: ${{ secrets.DOCKER_REGISTRY_ID }} - password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} + username: ${{ secrets.HARBOR_CENTREON_PUSH_USERNAME }} + password: ${{ secrets.HARBOR_CENTREON_PUSH_TOKEN }} - name: Login to Proxy Registry uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 diff --git a/.github/workflows/docker-gorgone-testing.yml b/.github/workflows/docker-gorgone-testing.yml index 6b8aa098d81..36e7d1b6094 100644 --- a/.github/workflows/docker-gorgone-testing.yml +++ b/.github/workflows/docker-gorgone-testing.yml @@ -24,28 +24,42 @@ jobs: dockerize: needs: [get-version] - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: matrix: - distrib: [alma8, alma9, bullseye, bookworm, jammy] + distrib: [alma8, alma9, bookworm] # No ubuntu in 24.10, 24.11 or later for now steps: - name: Checkout sources - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Login to registry uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 with: registry: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }} - username: ${{ secrets.DOCKER_REGISTRY_ID }} - password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} + username: ${{ secrets.HARBOR_CENTREON_PUSH_USERNAME }} + password: ${{ secrets.HARBOR_CENTREON_PUSH_TOKEN }} + + - name: Login to proxy registry + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 + with: + registry: ${{ vars.DOCKER_PROXY_REGISTRY_URL }} + username: ${{ secrets.HARBOR_CENTREON_PUSH_USERNAME }} + password: ${{ secrets.HARBOR_CENTREON_PUSH_TOKEN }} - uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # v3.6.1 - - uses: docker/build-push-action@5176d81f87c23d6fc96624dfdbcd9f3830bbe445 # v6.5.0 + - uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0 with: file: .github/docker/Dockerfile.gorgone-testing-${{ matrix.distrib }} context: . + build-args: | + "REGISTRY_URL=${{ vars.DOCKER_PROXY_REGISTRY_URL }}" + "VERSION=${{ needs.get-version.outputs.major_version }}" + "IS_CLOUD=${{ needs.get-version.outputs.release_cloud }}" pull: true push: true - tags: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/gorgone-testing-${{ matrix.distrib }}:${{ needs.get-version.outputs.gorgone_docker_version }} + tags: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/gorgone-testing-${{ matrix.distrib }}:${{ needs.get-version.outputs.major_version }} + secrets: | + "ARTIFACTORY_INTERNAL_REPO_USERNAME=${{ secrets.ARTIFACTORY_INTERNAL_REPO_USERNAME }}" + "ARTIFACTORY_INTERNAL_REPO_PASSWORD=${{ secrets.ARTIFACTORY_INTERNAL_REPO_PASSWORD }}" diff --git a/.github/workflows/get-version.yml b/.github/workflows/get-version.yml index 2ac04a47b19..b4689794d98 100644 --- a/.github/workflows/get-version.yml +++ b/.github/workflows/get-version.yml @@ -36,9 +36,6 @@ on: release_cloud: description: "context of release (cloud or not cloud)" value: ${{ jobs.get-version.outputs.release_cloud }} - gorgone_docker_version: - description: "md5 of gorgone dockerfile" - value: ${{ jobs.get-version.outputs.gorgone_docker_version }} jobs: get-version: @@ -54,11 +51,23 @@ jobs: environment: ${{ steps.get_version.outputs.env }} release_type: ${{ steps.get_version.outputs.release_type }} release_cloud: ${{ steps.get_version.outputs.release_cloud}} - gorgone_docker_version: ${{ steps.get_version.outputs.gorgone_docker_version }} steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + with: + ref: develop + path: centreon-collect-develop + sparse-checkout: .version + + - name: store latest major version + id: latest_major_version + run: | + . centreon-collect-develop/.version + echo "latest_major_version=$MAJOR" >> $GITHUB_OUTPUT + shell: bash + - name: install gh cli on self-hosted runner run: | if ! command -v gh &> /dev/null; then @@ -104,9 +113,6 @@ jobs: exit 1 fi - GORGONE_DOCKER_VERSION=$(cat .github/docker/Dockerfile.gorgone-testing-* | md5sum | cut -c1-8) - echo "gorgone_docker_version=$GORGONE_DOCKER_VERSION" >> $GITHUB_OUTPUT - IMG_VERSION=$( cat `ls .github/docker/Dockerfile.centreon-collect-* | grep -v test` vcpkg.json | md5sum | awk '{print substr($1, 0, 8)}') TEST_IMG_VERSION=$(cat .github/docker/Dockerfile.centreon-collect-*-test .github/scripts/collect-prepare-test-robot.sh resources/*.sql | md5sum | cut -c1-8) echo "img_version=$IMG_VERSION" >> $GITHUB_OUTPUT @@ -125,25 +131,31 @@ jobs: GITHUB_RELEASE_CLOUD=0 GITHUB_RELEASE_TYPE=$(echo $BRANCHNAME |cut -d '-' -f 1) + # if current branch major version has a matching dev-$MAJOR branch ==> onprem version + if git ls-remote -q | grep -E "refs/heads/dev-$MAJOR.x$" >/dev/null 2>&1; then + GITHUB_RELEASE_CLOUD=0 + # if current branch major version is greater or equal than the develop branch major version ==> cloud version + elif [[ "$(printf '%s\n' "${{ steps.latest_major_version.outputs.latest_major_version }}" "$MAJOR" | sort -V | head -n1)" == "${{ steps.latest_major_version.outputs.latest_major_version }}" ]]; then + GITHUB_RELEASE_CLOUD=1 + fi + case "$BRANCHNAME" in master) echo "release=1" >> $GITHUB_OUTPUT - echo "release_cloud=1" >> $GITHUB_OUTPUT + GITHUB_RELEASE_CLOUD=1 echo "release_type=$GITHUB_RELEASE_TYPE" >> $GITHUB_OUTPUT ;; [2-9][0-9].[0-9][0-9].x) echo "release=1" >> $GITHUB_OUTPUT - echo "release_cloud=$GITHUB_RELEASE_CLOUD" >> $GITHUB_OUTPUT echo "release_type=$GITHUB_RELEASE_TYPE" >> $GITHUB_OUTPUT ;; develop) echo "release=`date +%s`.`echo ${{ github.sha }} | cut -c -7`" >> $GITHUB_OUTPUT - echo "release_cloud=1" >> $GITHUB_OUTPUT + GITHUB_RELEASE_CLOUD=1 echo "release_type=$GITHUB_RELEASE_TYPE" >> $GITHUB_OUTPUT ;; dev-[2-9][0-9].[0-9][0-9].x) echo "release=`date +%s`.`echo ${{ github.sha }} | cut -c -7`" >> $GITHUB_OUTPUT - echo "release_cloud=0" >> $GITHUB_OUTPUT echo "release_type=$GITHUB_RELEASE_TYPE" >> $GITHUB_OUTPUT ;; release* | hotfix*) @@ -166,10 +178,8 @@ jobs: # Github ouputs echo "release=`date +%s`.`echo ${{ github.sha }} | cut -c -7`" >> $GITHUB_OUTPUT echo "release_type=$GITHUB_RELEASE_TYPE" >> $GITHUB_OUTPUT - echo "release_cloud=$GITHUB_RELEASE_CLOUD" >> $GITHUB_OUTPUT else echo "release=1" >> $GITHUB_OUTPUT - echo "release_cloud=$GITHUB_RELEASE_CLOUD" >> $GITHUB_OUTPUT echo "release_type=$GITHUB_RELEASE_TYPE" >> $GITHUB_OUTPUT fi ;; @@ -182,15 +192,15 @@ jobs: # Github ouputs echo "release=`date +%s`.`echo ${{ github.sha }} | cut -c -7`" >> $GITHUB_OUTPUT echo "release_type=$GITHUB_RELEASE_TYPE" >> $GITHUB_OUTPUT - echo "release_cloud=$GITHUB_RELEASE_CLOUD" >> $GITHUB_OUTPUT ;; *) echo "release=`date +%s`.`echo ${{ github.sha }} | cut -c -7`" >> $GITHUB_OUTPUT - echo "release_cloud=$GITHUB_RELEASE_CLOUD" >> $GITHUB_OUTPUT echo "release_type=$GITHUB_RELEASE_TYPE" >> $GITHUB_OUTPUT ;; esac + echo "release_cloud=$GITHUB_RELEASE_CLOUD" >> $GITHUB_OUTPUT + case "$BRANCHNAME" in develop | dev-[2-9][0-9].[0-9][0-9].x | prepare-release-cloud*) STABILITY="unstable" diff --git a/.github/workflows/gorgone.yml b/.github/workflows/gorgone.yml index d9ca865018b..acd9b069695 100644 --- a/.github/workflows/gorgone.yml +++ b/.github/workflows/gorgone.yml @@ -13,6 +13,7 @@ on: - reopened - ready_for_review paths: + - ".github/workflows/gorgone.yml" - "gorgone/**" - "!gorgone/tests/**" - "!gorgone/veracode.json" @@ -61,7 +62,7 @@ jobs: strategy: fail-fast: false matrix: - distrib: [el8, el9, bullseye, bookworm, jammy] + distrib: [el8, el9, bookworm] # No ubuntu in 24.10, 24.11 or later for now include: - package_extension: rpm image: packaging-nfpm-alma8 @@ -69,29 +70,23 @@ jobs: - package_extension: rpm image: packaging-nfpm-alma9 distrib: el9 - - package_extension: deb - image: packaging-nfpm-bullseye - distrib: bullseye - package_extension: deb image: packaging-nfpm-bookworm distrib: bookworm - - package_extension: deb - image: packaging-nfpm-jammy - distrib: jammy - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 container: image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ matrix.image }}:${{ needs.get-version.outputs.major_version }} credentials: - username: ${{ secrets.DOCKER_REGISTRY_ID }} - password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} + username: ${{ secrets.HARBOR_CENTREON_PUSH_USERNAME }} + password: ${{ secrets.HARBOR_CENTREON_PUSH_TOKEN }} name: package ${{ matrix.distrib }} steps: - name: Checkout sources - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Set package version and paths according to distrib run: | @@ -139,7 +134,7 @@ jobs: strategy: fail-fast: false matrix: - distrib: [el8, el9, bullseye, bookworm, jammy] + distrib: [el8, el9, bookworm] # No ubuntu in 24.10, 24.11 or later for now include: - package_extension: rpm image: gorgone-testing-alma8 @@ -147,22 +142,16 @@ jobs: - package_extension: rpm image: gorgone-testing-alma9 distrib: el9 - - package_extension: deb - image: gorgone-testing-bullseye - distrib: bullseye - - package_extension: deb - image: gorgone-testing-jammy - distrib: jammy - package_extension: deb image: gorgone-testing-bookworm distrib: bookworm - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 container: - image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ matrix.image }}:${{ needs.get-version.outputs.gorgone_docker_version }} + image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ matrix.image }}:${{ needs.get-version.outputs.major_version }} credentials: - username: ${{ secrets.DOCKER_REGISTRY_ID }} - password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} + username: ${{ secrets.HARBOR_CENTREON_PUSH_USERNAME }} + password: ${{ secrets.HARBOR_CENTREON_PUSH_TOKEN }} services: mariadb: @@ -189,10 +178,10 @@ jobs: shell: bash - name: Checkout sources - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Checkout sources - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 with: repository: centreon/centreon path: centreon @@ -208,14 +197,20 @@ jobs: key: ${{ github.sha }}-${{ github.run_id }}-${{ matrix.package_extension }}-${{ matrix.distrib }} fail-on-cache-miss: true - - name: Install gorgogne from just built package + - name: Parse distrib name + id: parse-distrib + uses: ./.github/actions/parse-distrib + with: + distrib: ${{ matrix.distrib }} + + - name: Install gorgone from just built package shell: bash run: | if [[ "${{ matrix.package_extension }}" == "deb" ]]; then apt update - apt install -y ./centreon-gorgone*${{ matrix.distrib }}* + apt install -y ./centreon-gorgone*${{ steps.parse-distrib.outputs.package_distrib_name }}* else - dnf install -y ./centreon-gorgone*${{ matrix.distrib }}* ./centreon-gorgone-centreon-config*${{ matrix.distrib }}* + dnf install -y ./centreon-gorgone*${{ steps.parse-distrib.outputs.package_distrib_name }}* ./centreon-gorgone-centreon-config*${{ steps.parse-distrib.outputs.package_distrib_name }}* # in el8 at least, there is a package for the configuration and a package for the actual code. # this is not the case for debian, and for now I don't know why it was made any different between the 2 Os. fi @@ -250,7 +245,7 @@ jobs: steps: - name: Checkout sources - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Deliver sources uses: ./.github/actions/release-sources @@ -273,7 +268,7 @@ jobs: steps: - name: Checkout sources - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Delivery uses: ./.github/actions/rpm-delivery @@ -294,11 +289,11 @@ jobs: strategy: matrix: - distrib: [bullseye, bookworm, jammy] + distrib: [bookworm] # No ubuntu in 24.10, 24.11 or later for now steps: - name: Checkout sources - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Delivery uses: ./.github/actions/deb-delivery @@ -313,16 +308,20 @@ jobs: release_cloud: ${{ needs.get-version.outputs.release_cloud }} promote: - needs: [get-version] - if: ${{ contains(fromJson('["stable"]'), needs.get-version.outputs.stability) && github.event_name != 'workflow_dispatch' }} + needs: [get-version, deliver-rpm, deliver-deb] + if: | + (contains(fromJson('["stable", "testing"]'), needs.get-version.outputs.stability) && github.event_name != 'workflow_dispatch') && + ! cancelled() && + ! contains(needs.*.result, 'failure') && + ! contains(needs.*.result, 'cancelled') runs-on: [self-hosted, common] strategy: matrix: - distrib: [el8, el9, bullseye, bookworm] + distrib: [el8, el9, bookworm] steps: - name: Checkout sources - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Promote ${{ matrix.distrib }} to stable uses: ./.github/actions/promote-to-stable diff --git a/.github/workflows/libzmq.yml b/.github/workflows/libzmq.yml index ad0adeb625a..bc342cc8d09 100644 --- a/.github/workflows/libzmq.yml +++ b/.github/workflows/libzmq.yml @@ -79,10 +79,6 @@ jobs: fail-fast: false matrix: include: - - image: packaging-nfpm-bullseye - distrib: bullseye - runner: ubuntu-22.04 - arch: amd64 - image: packaging-nfpm-bookworm distrib: bookworm runner: ubuntu-22.04 @@ -91,10 +87,6 @@ jobs: distrib: jammy runner: ubuntu-22.04 arch: amd64 - - image: packaging-bullseye-arm64 - distrib: bullseye - runner: ["self-hosted", "collect-arm64"] - arch: arm64 runs-on: ${{ matrix.runner }} @@ -107,6 +99,15 @@ jobs: name: package ${{ matrix.distrib }} ${{ matrix.arch }} steps: + - name: Checkout sources + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + + - name: Parse distrib name + id: parse-distrib + uses: ./.github/actions/parse-distrib + with: + distrib: ${{ matrix.distrib }} + - name: package deb run: | apt-get update @@ -122,7 +123,7 @@ jobs: wget -O - https://github.com/zeromq/libzmq/archive/refs/tags/v4.3.5.tar.gz | tar zxvf - cd libzmq-4.3.5 ln -s packaging/debian - sed -Ei 's/([0-9]+.[0-9]+.[0-9]+-[0-9]+.[0-9]+)/\1~${{ matrix.distrib }}/' debian/changelog + sed -Ei 's/([0-9]+.[0-9]+.[0-9]+-[0-9]+.[0-9]+)/\1${{ steps.parse-distrib.outputs.package_distrib_separator }}${{ steps.parse-distrib.outputs.package_distrib_name }}/' debian/changelog sed -Ei 's/UNRELEASED/${{ matrix.distrib }}/' debian/changelog dpkg-buildpackage -us -uc -nc cd .. @@ -175,14 +176,8 @@ jobs: strategy: matrix: include: - - distrib: bullseye - arch: amd64 - - distrib: bullseye - arch: arm64 - distrib: bookworm arch: amd64 - - distrib: jammy - arch: amd64 name: deliver ${{ matrix.distrib }} ${{ matrix.arch }} @@ -203,12 +198,16 @@ jobs: release_cloud: ${{ needs.get-version.outputs.release_cloud }} promote: - needs: [get-version] - if: ${{ contains(fromJson('["stable"]'), needs.get-version.outputs.stability) && github.event_name != 'workflow_dispatch' }} + needs: [get-version, deliver-rpm, deliver-deb] + if: | + (contains(fromJson('["stable", "testing"]'), needs.get-version.outputs.stability) && github.event_name != 'workflow_dispatch') && + ! cancelled() && + ! contains(needs.*.result, 'failure') && + ! contains(needs.*.result, 'cancelled') runs-on: [self-hosted, common] strategy: matrix: - distrib: [el8, el9, bullseye, bookworm, jammy] + distrib: [el8, el9, bookworm] steps: - name: Checkout sources diff --git a/.github/workflows/lua-curl.yml b/.github/workflows/lua-curl.yml index 402cc3bf640..a0051595337 100644 --- a/.github/workflows/lua-curl.yml +++ b/.github/workflows/lua-curl.yml @@ -47,12 +47,6 @@ jobs: lua_version: 5.4 runner: ubuntu-24.04 arch: amd64 - - package_extension: deb - image: centreon-collect-debian-bullseye - distrib: bullseye - lua_version: 5.3 - runner: ubuntu-24.04 - arch: amd64 - package_extension: deb image: centreon-collect-debian-bookworm distrib: bookworm @@ -65,12 +59,6 @@ jobs: lua_version: 5.3 runner: ubuntu-24.04 arch: amd64 - - package_extension: deb - image: centreon-collect-debian-bullseye-arm64 - distrib: bullseye - lua_version: 5.3 - runner: ["self-hosted", "collect-arm64"] - arch: arm64 - package_extension: deb image: centreon-collect-debian-bookworm-arm64 distrib: bookworm @@ -176,14 +164,9 @@ jobs: strategy: matrix: include: - - distrib: bullseye - arch: amd64 - - distrib: bullseye - arch: arm64 - distrib: bookworm arch: amd64 - - distrib: jammy - arch: amd64 + name: deliver ${{ matrix.distrib }} ${{ matrix.arch }} steps: @@ -203,12 +186,16 @@ jobs: release_cloud: ${{ needs.get-version.outputs.release_cloud }} promote: - needs: [get-version] - if: ${{ contains(fromJson('["stable"]'), needs.get-version.outputs.stability) && github.event_name != 'workflow_dispatch' }} + needs: [get-version, deliver-rpm, deliver-deb] + if: | + (contains(fromJson('["stable", "testing"]'), needs.get-version.outputs.stability) && github.event_name != 'workflow_dispatch') && + ! cancelled() && + ! contains(needs.*.result, 'failure') && + ! contains(needs.*.result, 'cancelled') runs-on: [self-hosted, common] strategy: matrix: - distrib: [el8, el9, bullseye, bookworm] + distrib: [el8, el9, bookworm] steps: - name: Checkout sources diff --git a/.github/workflows/package-collect.yml b/.github/workflows/package-collect.yml index d1b4299692c..4f101ca71fb 100644 --- a/.github/workflows/package-collect.yml +++ b/.github/workflows/package-collect.yml @@ -21,50 +21,32 @@ on: stability: required: true type: string + legacy_engine: + required: true + type: string + packages_in_artifact: + required: true + type: boolean + image: + required: true + type: string + distrib: + required: true + type: string + package_extension: + required: true + type: string + runner: + required: true + type: string + arch: + required: true + type: string + jobs: package: - strategy: - fail-fast: false - matrix: - include: - - image: centreon-collect-alma8 - distrib: el8 - package_extension: rpm - runner: collect - arch: amd64 - - image: centreon-collect-alma9 - distrib: el9 - package_extension: rpm - runner: collect - arch: amd64 - - image: centreon-collect-debian-bullseye - distrib: bullseye - package_extension: deb - runner: collect - arch: amd64 - - image: centreon-collect-debian-bookworm - distrib: bookworm - package_extension: deb - runner: collect - arch: amd64 - - image: centreon-collect-ubuntu-jammy - distrib: jammy - package_extension: deb - runner: collect - arch: amd64 - - image: centreon-collect-debian-bullseye-arm64 - distrib: bullseye - package_extension: deb - runner: collect-arm64 - arch: arm64 - - image: centreon-collect-debian-bookworm-arm64 - distrib: bookworm - package_extension: deb - runner: collect-arm64 - arch: arm64 - - runs-on: ${{ fromJson(format('["self-hosted", "{0}"]', matrix.runner)) }} + runs-on: ${{ fromJson(format('["self-hosted", "{0}"]', inputs.runner)) }} env: SCCACHE_PATH: "/usr/bin/sccache" @@ -74,12 +56,12 @@ jobs: AWS_SECRET_ACCESS_KEY: ${{ secrets.COLLECT_S3_SECRET_KEY }} container: - image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ matrix.image }}:${{ inputs.img_version }} + image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ inputs.image }}:${{ inputs.img_version }} credentials: username: ${{ secrets.DOCKER_REGISTRY_ID }} password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} - name: package ${{ matrix.distrib }} ${{ matrix.arch }} + name: package ${{ inputs.distrib }} ${{ inputs.arch }} steps: - name: Checkout sources @@ -87,17 +69,17 @@ jobs: - name: Install sccache run: | - if [ "${{ matrix.package_extension }}" = "deb" ]; then + if [ "${{ inputs.package_extension }}" = "deb" ]; then apt-get update apt-get install -y wget - elif [ "${{ matrix.package_extension }}" = "rpm" ]; then + elif [ "${{ inputs.package_extension }}" = "rpm" ]; then dnf install -y wget fi - if [ "${{ matrix.arch }}" = "amd64" ]; then + if [ "${{ inputs.arch }}" = "amd64" ]; then wget https://github.com/mozilla/sccache/releases/download/v0.8.1/sccache-v0.8.1-x86_64-unknown-linux-musl.tar.gz tar xzf sccache-v0.8.1-x86_64-unknown-linux-musl.tar.gz mv sccache-v0.8.1-x86_64-unknown-linux-musl/sccache /usr/bin/ - elif [ "${{ matrix.arch }}" = "arm64" ]; then + elif [ "${{ inputs.arch }}" = "arm64" ]; then wget https://github.com/mozilla/sccache/releases/download/v0.8.1/sccache-v0.8.1-aarch64-unknown-linux-musl.tar.gz tar xzf sccache-v0.8.1-aarch64-unknown-linux-musl.tar.gz mv sccache-v0.8.1-aarch64-unknown-linux-musl/sccache /usr/bin/ @@ -105,7 +87,7 @@ jobs: ${SCCACHE_PATH} --start-server - name: Generate selinux binaries - if: ${{ matrix.package_extension == 'rpm' }} + if: ${{ inputs.package_extension == 'rpm' }} run: | cd selinux for MODULE in "centreon-engine" "centreon-broker" "centreon-monitoring-agent"; do @@ -117,18 +99,18 @@ jobs: shell: bash - name: Remove selinux packaging files on debian - if: ${{ matrix.package_extension == 'deb' }} + if: ${{ inputs.package_extension == 'deb' }} run: rm -f packaging/*-selinux.yaml shell: bash - name: Compile sources run: | CMAKE="cmake3" - if [ "${{ matrix.package_extension }}" = "deb" ]; then + if [ "${{ inputs.package_extension }}" = "deb" ]; then CMAKE="cmake" fi - if [ "${{ matrix.arch }}" = "arm64" ]; then + if [ "${{ inputs.arch }}" = "arm64" ]; then export VCPKG_FORCE_SYSTEM_BINARIES=1 export TRIPLET=arm64-linux-release else @@ -162,7 +144,7 @@ jobs: -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DCMAKE_C_COMPILER_LAUNCHER=${SCCACHE_PATH} \ -DCMAKE_CXX_COMPILER_LAUNCHER=${SCCACHE_PATH} \ - -DLEGACY_ENGINE=ON \ + -DLEGACY_ENGINE=${{ inputs.legacy_engine }} \ -S . ninja -Cbuild @@ -204,14 +186,14 @@ jobs: - uses: ./.github/actions/package with: nfpm_file_pattern: "packaging/*.yaml" - distrib: ${{ matrix.distrib }} - package_extension: ${{ matrix.package_extension }} + distrib: ${{ inputs.distrib }} + package_extension: ${{ inputs.package_extension }} major_version: ${{ inputs.major_version }} minor_version: ${{ inputs.minor_version }} release: ${{ inputs.release }} - arch: ${{ matrix.arch }} + arch: ${{ inputs.arch }} commit_hash: ${{ inputs.commit_hash }} - cache_key: ${{ github.run_id }}-${{ github.sha }}-${{ matrix.package_extension}}-centreon-collect-${{ matrix.distrib }}-${{ matrix.arch }}-${{ github.head_ref || github.ref_name }} + cache_key: ${{ github.run_id }}-${{ github.sha }}-${{ inputs.package_extension}}-centreon-collect-${{ inputs.distrib }}-${{ inputs.arch }}-${{ github.head_ref || github.ref_name }} rpm_gpg_key: ${{ secrets.RPM_GPG_SIGNING_KEY }} rpm_gpg_signing_key_id: ${{ secrets.RPM_GPG_SIGNING_KEY_ID }} rpm_gpg_signing_passphrase: ${{ secrets.RPM_GPG_SIGNING_PASSPHRASE }} @@ -219,13 +201,13 @@ jobs: - name: Cleaning not needed packages shell: bash - run: rm -rf *-debuginfo*.${{ matrix.package_extension }} + run: rm -rf *-debuginfo*.${{ inputs.package_extension }} # set condition to true if artifacts are needed - - if: ${{ false }} + - if: inputs.packages_in_artifact == true name: Upload package artifacts uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 with: - name: packages-${{ matrix.distrib }}-${{ matrix.arch }} - path: ./*.${{ matrix.package_extension}} + name: packages-${{ inputs.distrib }}-${{ inputs.arch }} + path: ./*.${{ inputs.package_extension}} retention-days: 1 diff --git a/.github/workflows/windows-agent-robot-test.yml b/.github/workflows/windows-agent-robot-test.yml index 8d52099a14e..30abb02db7b 100644 --- a/.github/workflows/windows-agent-robot-test.yml +++ b/.github/workflows/windows-agent-robot-test.yml @@ -6,10 +6,125 @@ concurrency: on: workflow_dispatch: + schedule: + - cron: '30 0 * * *' jobs: - build-agent: + get-version: + uses: ./.github/workflows/get-version.yml + with: + version_file: CMakeLists.txt + + build-collect: + needs: [get-version] + uses: ./.github/workflows/package-collect.yml + with: + major_version: ${{ needs.get-version.outputs.major_version }} + minor_version: ${{ needs.get-version.outputs.minor_version }} + img_version: ${{ needs.get-version.outputs.img_version }} + release: ${{ needs.get-version.outputs.release }} + commit_hash: ${{ github.sha }} + stability: ${{ needs.get-version.outputs.stability }} + legacy_engine: 'ON' + packages_in_artifact: false + image: centreon-collect-debian-bullseye + distrib: bullseye + package_extension: deb + runner: collect + arch: amd64 + secrets: inherit + + + build-agent-and-execute-test: + needs: [build-collect] runs-on: windows-latest + + env: + AWS_ACCESS_KEY_ID: ${{ secrets.COLLECT_S3_ACCESS_KEY }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.COLLECT_S3_SECRET_KEY }} + steps: + - name: nocrlf conversion + run: git config --system core.autocrlf false + - name: Checkout sources uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + + + - name: distrib availables + run: wsl --list --online + + - name: install debian + uses: Vampire/setup-wsl@v3 + with: + distribution: Debian + use-cache: 'true' + update: 'true' + additional-packages: + mariadb-server + libmariadb3 + librrd8 + liblua5.3 + python3 + python3-pip + rrdtool + + - name: IP info + run: | + Write-Host "ip config" + ipconfig /all + Write-Host "ip address show" + wsl ip address show + + - name: install robot framework + run: | + wsl pip3 install -U robotframework robotframework-databaselibrary robotframework-examples + wsl pip3 install pymysql python-dateutil grpcio grpcio_tools psutil + + - name: Compile Agent + run: .github/scripts/windows-agent-compile.ps1 + shell: powershell + + - name: install database + run: | + $current_dir = (pwd).Path + $wsl_path = "/mnt/" + $current_dir.SubString(0,1).ToLower() + "/" + $current_dir.SubString(3).replace('\','/') + Write-Host "install mariadb" + wsl cd $wsl_path `&`& .github/scripts/collect-setup-database.sh + + - name: Restore packages + uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 + with: + path: ./*.deb + key: ${{ github.run_id }}-${{ github.sha }}-deb-centreon-collect-bullseye-amd64-${{ github.head_ref || github.ref_name }} + fail-on-cache-miss: true + enableCrossOsArchive: true + + - name: list packages + run: | + $current_dir = (pwd).Path + $wsl_path = "/mnt/" + $current_dir.SubString(0,1).ToLower() + "/" + $current_dir.SubString(3).replace('\','/') + wsl ls -l $wsl_path + + - name: install collect packages + run: | + $current_dir = (pwd).Path + $wsl_path = "/mnt/" + $current_dir.SubString(0,1).ToLower() + "/" + $current_dir.SubString(3).replace('\','/') + wsl cd $wsl_path `&`& dpkg -i --force-all ./*.deb + + - name: prepare robot tests + run: | + copy tests\resources\engine-scripts\echo.ps1 C:\Users\public\ + copy tests\resources\engine-scripts\check.ps1 C:\Users\public\ + + - name: robot tests + run: .github/scripts/agent_robot_test.ps1 + shell: powershell + + - name: Upload Test Results + if: ${{ failure() }} + uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 + with: + name: reports-cma-windows + path: reports + retention-days: 1 diff --git a/.github/workflows/windows-agent.yml b/.github/workflows/windows-agent.yml index 3e6b132ab68..ffd3033a623 100644 --- a/.github/workflows/windows-agent.yml +++ b/.github/workflows/windows-agent.yml @@ -6,6 +6,13 @@ concurrency: on: workflow_dispatch: + inputs: + installer_in_artifact: + description: 'Save installer and binary in artifacts' + required: true + default: false + type: boolean + pull_request: paths: - agent/** @@ -40,6 +47,15 @@ jobs: AWS_SECRET_ACCESS_KEY: ${{ secrets.COLLECT_S3_SECRET_KEY }} steps: + - uses: jfrog/setup-jfrog-cli@26da2259ee7690e63b5410d7451b2938d08ce1f9 # v4.0.0 + env: + JF_URL: https://centreon.jfrog.io + JF_ACCESS_TOKEN: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} + + # in order to have the same checksum between windows-agent and windows-agent-robot-test + - name: No crlf conversion + run: git config --system core.autocrlf false + - name: Checkout sources uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 @@ -57,27 +73,63 @@ jobs: cd build_windows tests/ut_agent - - name: Zip agent - run: | - $files_to_compress = "agent\conf\centagent.reg", "build_windows\agent\Release\centagent.exe" - Compress-Archive -Path $files_to_compress -DestinationPath centreon-monitoring-agent.zip + - name: Installer test + run: .github/scripts/agent_installer_test.ps1 + shell: powershell - - name: Save agent package in cache - uses: actions/cache/save@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 + - name: Upload package artifacts + if: | + inputs.installer_in_artifact == true + uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 with: - path: centreon-monitoring-agent.zip - key: ${{ github.run_id }}-${{ github.sha }}-CMA-${{ github.head_ref || github.ref_name }} - enableCrossOsArchive: ${{ true }} + name: packages-centreon-monitoring-agent-windows + path: agent\installer\centreon-monitoring-agent.exe - - name: Upload package artifacts + - name: Deliver if: | - github.event_name != 'workflow_dispatch' && - contains(fromJson('["stable"]'), needs.get-version.outputs.stability) && + contains(fromJson('["unstable", "testing"]'), needs.get-version.outputs.stability) && ! cancelled() && ! contains(needs.*.result, 'failure') && ! contains(needs.*.result, 'cancelled') - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 - with: - name: packages-centreon-monitoring-agent-windows - path: centreon-monitoring-agent.zip - retention-days: 1 + run: | + Write-Host "[DEBUG] deliver to testing - Major version: ${{ needs.get-version.outputs.major_version }}" + Write-Host "[DEBUG] deliver to testing - Minor version: ${{ needs.get-version.outputs.minor_version }}" + + $VERSION = "${{ needs.get-version.outputs.version }}" + $MODULE_NAME = "monitoring-agent-$VERSION" + $STABILITY = "${{ needs.get-version.outputs.stability }}" + + $TARGET_PATH = "installers/monitoring-agent/${{ needs.get-version.outputs.major_version }}/$STABILITY/$MODULE_NAME/" + + $VERSION_EXE = "centreon-monitoring-agent-${VERSION}.exe" + + Copy-Item -Path "agent\installer\centreon-monitoring-agent.exe" -Destination "${VERSION_EXE}" + Write-Host "[DEBUG] deliver testing to - Target path: ${TARGET_PATH}" + jf rt upload $VERSION_EXE "${TARGET_PATH}" --sync-deletes="${TARGET_PATH}" + + + - name: Promote testing to stable + if: | + needs.get-version.outputs.stability == 'stable' && github.event_name != 'workflow_dispatch' && ! cancelled() + run: | + Write-Host "[DEBUG] promote to stable - Major version: ${{ needs.get-version.outputs.major_version }}" + Write-Host "[DEBUG] promote to stable - Minor version: ${{ needs.get-version.outputs.minor_version }}" + + $VERSION= "${{ needs.get-version.outputs.version }}" + $MODULE_NAME= "monitoring-agent-${{ needs.get-version.outputs.version }}" + $STABILITY= "${{ needs.get-version.outputs.stability }}" + + $SRC_PATH = "installers/monitoring-agent/${{ needs.get-version.outputs.major_version }}/testing/$MODULE_NAME/" + $TARGET_PATH = "installers/monitoring-agent/${{ needs.get-version.outputs.major_version }}/$STABILITY/$MODULE_NAME/" + + $VERSION_EXE = "centreon-monitoring-agent-${VERSION}.exe" + + Write-Host "[DEBUG] promote to stable from: ${SRC_PATH}${VERSION_EXE}" + + jf rt download "${SRC_PATH}${VERSION_EXE}" --flat + + Write-Host "[DEBUG] promote to stable ${VERSION_EXE} to path: ${TARGET_PATH}" + + jf rt upload $VERSION_EXE "${TARGET_PATH}" --sync-deletes="${TARGET_PATH}" + + shell: powershell diff --git a/.gitignore b/.gitignore index e783d4cbb85..4ce637ed29b 100644 --- a/.gitignore +++ b/.gitignore @@ -35,8 +35,9 @@ ut ### apps/ -build/* +build*/* tests/failed/* +.vs ### ide ### **/.vscode/ diff --git a/.version b/.version index db9a189ef29..36f30465402 100644 --- a/.version +++ b/.version @@ -1,2 +1,2 @@ -MAJOR=24.09 +MAJOR=24.11 MINOR=0 diff --git a/CMakeLists.txt b/CMakeLists.txt index 51319732e2a..e8433be844c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -118,7 +118,7 @@ endif() # Version. set(COLLECT_MAJOR 24) -set(COLLECT_MINOR 09) +set(COLLECT_MINOR 11) set(COLLECT_PATCH 0) set(COLLECT_VERSION "${COLLECT_MAJOR}.${COLLECT_MINOR}.${COLLECT_PATCH}") diff --git a/CMakeListsLinux.txt b/CMakeListsLinux.txt index 00360bf7827..5f1e941fb9d 100644 --- a/CMakeListsLinux.txt +++ b/CMakeListsLinux.txt @@ -39,7 +39,10 @@ option(WITH_MALLOC_TRACE "compile centreon-malloc-trace library." OFF) option(DEBUG_ROBOT OFF) if(LEGACY_ENGINE) + message(STATUS "Collect compilation with the legacy Engine configuration library.") add_definitions(-DLEGACY_CONF) +else() + message(STATUS "Collect compilation with the Protobuf Engine configuration library.") endif() if(WITH_TSAN) diff --git a/CMakePresets.json b/CMakePresets.json index e94d5ad68b9..b8d69e2a906 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -24,4 +24,4 @@ } } ] -} \ No newline at end of file +} diff --git a/agent/CMakeLists.txt b/agent/CMakeLists.txt index 510a237da98..d2af2dfaae8 100644 --- a/agent/CMakeLists.txt +++ b/agent/CMakeLists.txt @@ -97,8 +97,17 @@ add_custom_command( ${PROJECT_SOURCE_DIR}/proto/agent.proto WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") + set(NATIVE_DIR "native_linux") +else() + set(NATIVE_DIR "native_windows") +endif() + +set(NATIVE_INC "${PROJECT_SOURCE_DIR}/${NATIVE_DIR}/inc/com/centreon/agent") +set(NATIVE_SRC "${PROJECT_SOURCE_DIR}/${NATIVE_DIR}/src") set( SRC_COMMON + ${NATIVE_SRC}/check_cpu.cc ${SRC_DIR}/agent.grpc.pb.cc ${SRC_DIR}/agent.pb.cc ${SRC_DIR}/bireactor.cc @@ -122,6 +131,9 @@ set( SRC_LINUX ${SRC_DIR}/config.cc ) +#resource version +configure_file("${SRC_DIR}/agent.rc.in" + "${SRC_DIR}/agent.rc") configure_file("${INCLUDE_DIR}/version.hh.in" "${INCLUDE_DIR}/version.hh") @@ -138,7 +150,8 @@ add_library(centagent_lib STATIC ) include_directories( - ${INCLUDE_DIR} + ${INCLUDE_DIR} + ${NATIVE_INC} ${SRC_DIR} ${CMAKE_SOURCE_DIR}/common/inc ${CMAKE_SOURCE_DIR}/common/grpc/inc @@ -165,7 +178,7 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") fmt::fmt stdc++fs) else() - add_executable(${CENTREON_AGENT} ${SRC_DIR}/main_win.cc) + add_executable(${CENTREON_AGENT} ${SRC_DIR}/main_win.cc ${SRC_DIR}/agent.rc) target_link_libraries( ${CENTREON_AGENT} PRIVATE @@ -177,6 +190,9 @@ else() absl::any absl::log absl::base absl::bits Boost::program_options fmt::fmt) + + add_subdirectory(installer) + endif() diff --git a/agent/doc/agent-doc.md b/agent/doc/agent-doc.md index 8d92a4b3ee7..7f279210860 100644 --- a/agent/doc/agent-doc.md +++ b/agent/doc/agent-doc.md @@ -10,6 +10,8 @@ The configuration is given by Engine by an AgentConfiguration message sent over The configuration object is embedded in MessageToAgent::config ## Scheduler +Scheduler is created when a server service (revers connection is created) or when agent creates a service client. +At this time he doesn't know the list of checks to execute. He begins to execute checks when he receives the an AgentConfiguration message. We try to spread checks over the check_period. Example: We have 10 checks to execute during one second. Check1 will start at now, second at now + 0.1s.. @@ -22,3 +24,59 @@ In the previous example, the second check for the first service will be schedule In case of check duration is too long, we might exceed maximum of concurrent checks. In that case checks will be executed as soon one will be ended. This means that the second check may start later than the scheduled time point (12:00:10) if the other first checks are too long. The order of checks is always respected even in case of a bottleneck. For example, a check lambda has a start_expected to 12:00, because of bottleneck, it starts at 12:15. Next start_expected of check lambda will then be 12:15 + check_period. + + +## native checks +All checks are scheduled by one thread, no mutex needed. +In order to add a native check, you need to inherit from check class. +Then you have to override constructor and start_check method. +All is asynchronous. When start_check is called, it must not block caller for a long time. +At the end of measure, it must call check::on_completion(). +That method need 4 arguments: +* start_check_index: For long asynchronous operation, at the beginning, asynchronous job must store running_index and use it when he have to call check::on_completion(). It is useful for scheduler to check is the result is the result of the last asynchronous job start. The new class can get running index with check::_get_running_check_index() +* status: plugins status equivalent. Values are 0:Ok, 1: warning, 2: critical, 3: unknown (https://nagios-plugins.org/doc/guidelines.html#AEN41) +* perfdata: a list of com::centreon::common::perfdata objects +* outputs: equivalent of plugins output as "CPU 54% OK" + +BEWARE, in some cases, we can have recursion, check::on_completion can call start_check + +A little example: +```c++ +class dummy_check : public check { + duration _command_duration; + asio::system_timer _command_timer; + + public: + void start_check(const duration& timeout) override { + check::start_check(timeout); + _command_timer.expires_from_now(_command_duration); + _command_timer.async_wait([me = shared_from_this(), this, + running_index = _get_running_check_index()]( + const boost::system::error_code& err) { + if (err) { + return; + } + on_completion(running_index, 1, + std::list(), + {"output dummy_check of " + get_command_line()}); + }); + } + + template + dummy_check(const std::string& serv, + const std::string& command_name, + const std::string& command_line, + const duration& command_duration, + handler_type&& handler) + : check(g_io_context, + spdlog::default_logger(), + std::chrono::system_clock::now(), + serv, + command_name, + command_line, + nullptr, + handler), + _command_duration(command_duration), + _command_timer(*g_io_context) {} +}; +``` \ No newline at end of file diff --git a/agent/inc/com/centreon/agent/scheduler.hh b/agent/inc/com/centreon/agent/scheduler.hh index b1ed36edfbc..bc96f39477b 100644 --- a/agent/inc/com/centreon/agent/scheduler.hh +++ b/agent/inc/com/centreon/agent/scheduler.hh @@ -151,6 +151,16 @@ class scheduler : public std::enable_shared_from_this { void stop(); + static std::shared_ptr default_check_builder( + const std::shared_ptr& io_context, + const std::shared_ptr& logger, + time_point start_expected, + const std::string& service, + const std::string& cmd_name, + const std::string& cmd_line, + const engine_to_agent_request_ptr& conf, + check::completion_handler&& handler); + engine_to_agent_request_ptr get_last_message_to_agent() const { return _conf; } diff --git a/agent/installer/CMakeLists.txt b/agent/installer/CMakeLists.txt new file mode 100644 index 00000000000..7f9cd769439 --- /dev/null +++ b/agent/installer/CMakeLists.txt @@ -0,0 +1,64 @@ +# +# Copyright 2024 Centreon +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# +# For more information : contact@centreon.com +# + +project("Centreon agent Installer") + + +# Set directories. +set(CENTAGENT_PATH_OUTPUT_DIR ${Centreon\ agent_BINARY_DIR}) + +if( ${CMAKE_GENERATOR} MATCHES "Visual Studio.*" ) + set(CENTAGENT_PATH "${Centreon\ agent_BINARY_DIR}/${CMAKE_BUILD_TYPE}/centagent.exe") +else() + set(CENTAGENT_PATH "${Centreon\ agent_BINARY_DIR}/centagent.exe") +endif() + +string(REPLACE "/" "\\" CENTAGENT_PATH "${CENTAGENT_PATH}") + +#uncomment if makensis is not in the path +set(MKNSIS "C:/Program Files (x86)/NSIS/Bin/makensis.exe") + +#set(MKNSIS "makensis.exe") + +# Configure files. +configure_file("${PROJECT_SOURCE_DIR}/version.nsi.in" "${PROJECT_SOURCE_DIR}/version.nsi") + +file(GLOB COMMON_INSTALLERS_FILES "${PROJECT_SOURCE_DIR}/version.nsi" "${PROJECT_SOURCE_DIR}/dlg_helper.nsi" "${PROJECT_SOURCE_DIR}/resources/*") + +message(NOTICE "---------------- Generate installer in ${PROJECT_SOURCE_DIR} ---------------") + +# modify binary called from the application manager +# embedded in installer +add_custom_command( + DEPENDS "${PROJECT_SOURCE_DIR}/centreon-monitoring-agent-modify.nsi" ${COMMON_INSTALLERS_FILES} ${CENTREON_AGENT} + COMMENT "--------- Generating cma configuration modifier --------" + OUTPUT "${PROJECT_SOURCE_DIR}/centreon-monitoring-agent-modify.exe" + WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" + COMMAND ${MKNSIS} "${PROJECT_SOURCE_DIR}/centreon-monitoring-agent-modify.nsi") + + +#final installer +add_custom_command( + DEPENDS "${PROJECT_SOURCE_DIR}/centreon-monitoring-agent.nsi" "${PROJECT_SOURCE_DIR}/centreon-monitoring-agent-modify.exe" ${COMMON_INSTALLERS_FILES} + COMMENT "--------- Generating cma configuration installer --------" + OUTPUT "${PROJECT_SOURCE_DIR}/centreon-monitoring-agent.exe" + WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" + COMMAND ${MKNSIS} "${PROJECT_SOURCE_DIR}/centreon-monitoring-agent.nsi") + +add_custom_target("centreon-monitoring-agent-installer" ALL DEPENDS "${PROJECT_SOURCE_DIR}/centreon-monitoring-agent.exe") + diff --git a/agent/installer/centreon-monitoring-agent-modify.nsi b/agent/installer/centreon-monitoring-agent-modify.nsi new file mode 100644 index 00000000000..4f15ee8d9d5 --- /dev/null +++ b/agent/installer/centreon-monitoring-agent-modify.nsi @@ -0,0 +1,157 @@ +# +# Copyright 2024 Centreon +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# +# For more information : contact@centreon.com +# + +XPStyle on + +Unicode false + +!define APPNAME "CentreonMonitoringAgent" +!define COMPANYNAME "Centreon" +!define DESCRIPTION "The Centreon Monitoring Agent (CMA) collects metrics and computes statuses on the servers it monitors, and sends them to Centreon." + +!define SERVICE_NAME ${APPNAME} + +!define CMA_REG_KEY "SOFTWARE\${COMPANYNAME}\${APPNAME}" + +#Match to windows file path C:\tutu yoyo1234 titi\fgdfgdg.rt +!define FILE_PATH_REGEXP '^[a-zA-Z]:([\\|\/](([\w\.]+\s+)*[\w\.]+)+)+$$' + + +!include "LogicLib.nsh" +!include "nsDialogs.nsh" +!include "mui.nsh" +!include "Sections.nsh" +!include "StrFunc.nsh" +!include "FileFunc.nsh" + +!include "nsis_service_lib.nsi" + +${Using:StrFunc} StrCase + +!define NSISCONF_3 ";" ; NSIS 2 tries to parse some preprocessor instructions inside "!if 0" blocks! +!addincludedir "nsis_pcre" +!define /redef NSISCONF_3 "" +${NSISCONF_3}!addplugindir /x86-ansi "nsis_pcre" +!undef NSISCONF_3 + + +!include "version.nsi" +!include "resources\setup_dlg.nsdinc" +!include "resources\encryption_dlg.nsdinc" +!include "resources\log_dlg.nsdinc" +#let it after dialog boxes +!include "dlg_helper.nsi" +!include "silent.nsi" + +Name "Centreon Monitoring Agent ${VERSIONMAJOR}.${VERSIONMINOR}.${VERSIONBUILD}" +Icon "resources/logo_centreon.ico" +RequestExecutionLevel admin + +VIProductVersion "${VERSIONMAJOR}.${VERSIONMINOR}.${VERSIONBUILD}.0" +VIFileVersion "${VERSIONMAJOR}.${VERSIONMINOR}.${VERSIONBUILD}.0" +VIAddVersionKey "FileVersion" "${VERSIONMAJOR}.${VERSIONMINOR}.${VERSIONBUILD}" +VIAddVersionKey "LegalCopyright" "2024 Centreon" +VIAddVersionKey "FileDescription" "Centreon Monitoring Agent Config modifier" +VIAddVersionKey "ProductName" "Centreon Monitoring Agent" +VIAddVersionKey "CompanyName" "Centreon" +VIAddVersionKey "ProductVersion" "${VERSIONMAJOR}.${VERSIONMINOR}.${VERSIONBUILD}.0" + + +!macro VerifyUserIsAdmin +UserInfo::GetAccountType +pop $0 +${If} $0 != "admin" ;Require admin rights + messageBox mb_iconstop "Administrator rights required!" + setErrorLevel 740 ;ERROR_ELEVATION_REQUIRED + quit +${EndIf} +!macroend + + +Function restart_cma + !insertmacro SERVICE "stop" "${SERVICE_NAME}" "" + + ;wait for service stop + StrCpy $0 "" + ${Do} + Push "running" + Push ${SERVICE_NAME} + Push "" + Call Service + Pop $0 + ${If} $0 != "true" + ${Break} + ${EndIf} + Sleep 500 + ${Loop} + ; even if service is stopped, process can be stopping so we wait a little more + Sleep 1000 + + !insertmacro SERVICE "start" "${SERVICE_NAME}" "" +FunctionEnd + + +Function .onInit + setShellVarContext all + ${If} ${Silent} + SetErrorLevel 0 + ${GetParameters} $cmdline_parameters + StrCpy $1 "--no_reverse Set this flag if you want to disable Poller-initiated connection$\n\ +--no_encryption Set this flag if you want to disable encryption $\n" + Call show_help + call show_version + Call silent_verify_admin + Call silent_update_conf + + Call restart_cma + System::Call 'kernel32::AttachConsole(i -1)i.r0' ;attach to parent console + System::Call 'kernel32::GetStdHandle(i -11)i.r0' ;console attached -- get stdout + FileWrite $0 "Centreon monitoring agent configured and restarted$\n" + Quit + ${Else} + !insertmacro VerifyUserIsAdmin + ${EndIf} +FunctionEnd + +/** + * @brief at the end of the installer, we stop and start cma +*/ +Function encryption_next_and_restart_centagent + Call encryption_dlg_onNext + Call restart_cma + MessageBox MB_OK "The Centreon Monitoring Agent has now restarted" + Quit +FunctionEnd + + +/** + * @brief this fake page is used to have a close button after restart cma confirmation +*/ +Function dummy_page +FunctionEnd + +Page custom fnc_cma_Show setup_dlg_onNext +Page custom fnc_log_dlg_Show log_dlg_onNext ": logging" +Page custom fnc_encryption_Show encryption_next_and_restart_centagent ": encryption" +Page custom dummy_page + +/** + * @brief this installer only update agent config, no installation +*/ +Section "update config" +SectionEnd \ No newline at end of file diff --git a/agent/installer/centreon-monitoring-agent.nsi b/agent/installer/centreon-monitoring-agent.nsi new file mode 100644 index 00000000000..163d57a1ee0 --- /dev/null +++ b/agent/installer/centreon-monitoring-agent.nsi @@ -0,0 +1,367 @@ +# +# Copyright 2024 Centreon +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# +# For more information : contact@centreon.com +# + +XPStyle on + +Unicode false + +!define APPNAME "CentreonMonitoringAgent" +!define COMPANYNAME "Centreon" +!define DESCRIPTION "The Centreon Monitoring Agent (CMA) collects metrics and computes statuses on the servers it monitors, and sends them to Centreon." + +!define SERVICE_NAME ${APPNAME} + +!define CMA_REG_KEY "SOFTWARE\${COMPANYNAME}\${APPNAME}" + +#Match to windows file path C:\tutu yoyo1234 titi\fgdfgdg.rt +!define FILE_PATH_REGEXP '^[a-zA-Z]:([\\|\/](([\w\.]+\s+)*[\w\.]+)+)+$$' + +!define UNINSTALL_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" + +!define NSCLIENT_URL "https://api.github.com/repos/centreon/centreon-nsclient-build/releases/latest" + +!define NSISCONF_3 ";" ; NSIS 2 tries to parse some preprocessor instructions inside "!if 0" blocks! +!addincludedir "nsis_pcre" +!define /redef NSISCONF_3 "" +${NSISCONF_3}!addplugindir /x86-ansi "nsis_pcre" +${NSISCONF_3}!addplugindir /x86-ansi "inetc/Plugins/x86-ansi" +${NSISCONF_3}!addplugindir /x86-ansi "ns_json/Plugins/x86-ansi" +!undef NSISCONF_3 + + +!include "LogicLib.nsh" +!include "nsDialogs.nsh" +!include "mui.nsh" +!include "Sections.nsh" +!include "StrFunc.nsh" +!include "FileFunc.nsh" + +!include "nsis_service_lib.nsi" + +${Using:StrFunc} StrCase + +!include "version.nsi" +!include "resources\setup_dlg.nsdinc" +!include "resources\encryption_dlg.nsdinc" +!include "resources\log_dlg.nsdinc" +#let it after dialog boxes +!include "dlg_helper.nsi" + +!include "silent.nsi" + +OutFile "centreon-monitoring-agent.exe" +Name "Centreon Monitoring Agent ${VERSIONMAJOR}.${VERSIONMINOR}.${VERSIONBUILD}" +Icon "resources/logo_centreon.ico" +LicenseData "resources/license.txt" +RequestExecutionLevel admin +;AllowRootDirInstall true + +VIProductVersion "${VERSIONMAJOR}.${VERSIONMINOR}.${VERSIONBUILD}.0" +VIFileVersion "${VERSIONMAJOR}.${VERSIONMINOR}.${VERSIONBUILD}.0" +VIAddVersionKey "FileVersion" "${VERSIONMAJOR}.${VERSIONMINOR}.${VERSIONBUILD}" +VIAddVersionKey "LegalCopyright" "2024 Centreon" +VIAddVersionKey "FileDescription" "Centreon Monitoring Agent Installer" +VIAddVersionKey "ProductName" "Centreon Monitoring Agent" +VIAddVersionKey "CompanyName" "Centreon" +VIAddVersionKey "ProductVersion" "${VERSIONMAJOR}.${VERSIONMINOR}.${VERSIONBUILD}.0" + + +InstallDir "$PROGRAMFILES64\${COMPANYNAME}\${APPNAME}" +!define PLUGINS_DIR "$PROGRAMFILES64\${COMPANYNAME}\Plugins" + +!define HELPURL "https://www.centreon.com/" + +Var plugins_url + + + +!macro verify_user_is_admin +UserInfo::GetAccountType +pop $0 +${If} $0 != "admin" ;Require admin rights + messageBox mb_iconstop "Administrator rights required!" + setErrorLevel 740 ;ERROR_ELEVATION_REQUIRED + quit +${EndIf} +!macroend + + + +/** + * @brief pages +*/ +page license +Page components +Page custom setup_cma_show setup_dlg_onNext +Page custom setup_log_show log_dlg_onNext ": logging" +Page custom setup_cma_encryption_show encryption_dlg_onNext ": encryption" +Page instfiles + +/** + * @brief first it uses github API to get information of centreon-nsclient-build last releases. + * Then it gets a json response where one asset is the asset of centreon plugins + * +*/ +Function get_plugins_url + #because of several bugs, we have to store github response in a file and then parse it + Var /GLOBAL json_content_path + Var /GLOBAL nb_assets + GetTempFileName $json_content_path + #get release information + ClearErrors + inetc::get /header "Accept: application/vnd.github+json" ${NSCLIENT_URL} $json_content_path /End + ${If} ${Errors} + MessageBox MB_OK|MB_ICONSTOP "Failed to get plugin information from ${NSCLIENT_URL}" + Abort + ${EndIf} + Pop $0 + ${If} $0 != "OK" + MessageBox MB_OK|MB_ICONSTOP "Failed to get plugin information from ${NSCLIENT_URL}: $0" + Abort + ${EndIf} + + #parse json response + nsJSON::Set /file $json_content_path + ${If} ${Errors} + MessageBox MB_OK|MB_ICONSTOP "bad json received from ${NSCLIENT_URL}" + Abort + ${EndIf} + + nsJSON::Get /count `assets` /end + Pop $nb_assets + + ${ForEach} $0 0 $nb_assets + 1 + ClearErrors + nsJSON::Get "assets" /index $0 "name" + ${IfNot} ${Errors} + Pop $1 + ${If} $1 == "centreon_plugins.exe" + nsJSON::Get "assets" /index $0 "browser_download_url" + Pop $plugins_url + Return + ${EndIf} + ${EndIf} + ${Next} + + MessageBox MB_OK|MB_ICONSTOP "No Plugins Asset found at ${NSCLIENT_URL}" + Abort + +FunctionEnd + +/** + * @brief this section download plugings from the asset of the last centreon-nsclient-build release +*/ +Section "Plugins" PluginsInstSection + Call get_plugins_url + CreateDirectory ${PLUGINS_DIR} + DetailPrint "download plugins from $plugins_url" + inetc::get /caption "plugins" /banner "Downloading plugins..." "$plugins_url" "${PLUGINS_DIR}/centreon_plugins.exe" + ${If} ${Silent} + System::Call 'kernel32::AttachConsole(i -1)i.r0' ;attach to parent console + System::Call 'kernel32::GetStdHandle(i -11)i.r0' ;console attached -- get stdout + FileWrite $0 "Centreon plugins installed$\n" + ${EndIf} +SectionEnd + + +/** + * @brief this section configure and install centreon monitoring agent +*/ +Section "Centreon Monitoring Agent" CMAInstSection + SetRegView 64 + #event logger + WriteRegDWORD HKLM "SYSTEM\CurrentControlSet\Services\EventLog\Application\${SERVICE_NAME}" "TypesSupported" 7 + WriteRegExpandStr HKLM "SYSTEM\CurrentControlSet\Services\EventLog\Application\${SERVICE_NAME}" "EventMessageFile" "%systemroot%\System32\mscoree.dll" + setOutPath $INSTDIR + + !insertmacro SERVICE "stop" "${SERVICE_NAME}" "" + + #wait for service stop + StrCpy $0 "" + ${Do} + Push "running" + Push ${SERVICE_NAME} + Push "" + Call Service + Pop $0 + ${If} $0 != "true" + ${Break} + ${EndIf} + Sleep 500 + ${Loop} + # even if service is stopped, process can be stopping so we wait a little more + Sleep 500 + + file ${CENTAGENT_PATH} + file "centreon-monitoring-agent-modify.exe" + writeUninstaller "$INSTDIR\uninstall.exe" + + #create and start service + !insertmacro SERVICE "create" "${SERVICE_NAME}" \ + "path=$INSTDIR\centagent.exe;autostart=1;display=Centreon Monitoring Agent;\ + starttype=${SERVICE_AUTO_START};servicetype=${SERVICE_WIN32_OWN_PROCESS}" + !insertmacro SERVICE "start" "${SERVICE_NAME}" "" + + #uninstall information + WriteRegStr HKLM "${UNINSTALL_KEY}" "DisplayName" "Centreon Monitoring Agent" + WriteRegStr HKLM "${UNINSTALL_KEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\"" + WriteRegStr HKLM "${UNINSTALL_KEY}" "ModifyPath" "$\"$INSTDIR\centreon-monitoring-agent-modify.exe$\"" + ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 + IntFmt $0 "0x%08X" $0 + WriteRegDWORD HKLM "${UNINSTALL_KEY}" "EstimatedSize" "$0" + + ${If} ${Silent} + System::Call 'kernel32::AttachConsole(i -1)i.r0' ;attach to parent console + System::Call 'kernel32::GetStdHandle(i -11)i.r0' ;console attached -- get stdout + FileWrite $0 "Centreon monitoring agent installed and started$\n" + ${EndIf} +SectionEnd + + +/** + * @brief function called on install +*/ +function .onInit + setShellVarContext all + + ${If} ${Silent} + SetErrorLevel 0 + ${GetParameters} $cmdline_parameters + Strcpy $1 "--install_cma Set this flag if you want to install centreon monitoring agent$\n\ +--install_plugins Set this flag if you want to install centreon plugins$\n" + Call show_help + Call show_version + Call silent_verify_admin + + Call installer_parse_cmd_line + + ${If} $silent_install_cma == 1 + Call cmd_line_to_registry + SectionSetFlags ${CMAInstSection} ${SF_SELECTED} + ${Else} + SectionSetFlags ${CMAInstSection} 0 + ${EndIf} + + ${If} $silent_install_plugins == 1 + SectionSetFlags ${PluginsInstSection} ${SF_SELECTED} + ${Else} + SectionSetFlags ${PluginsInstSection} 0 + ${EndIf} + + ${Else} + !insertmacro verify_user_is_admin + ${EndIf} + +functionEnd + +/** + * @brief show cma setup dialogbox ig user has choosen to install cma +*/ +Function setup_cma_show + ${If} ${SectionIsSelected} ${CMAInstSection} + Call fnc_cma_Show + ${EndIf} +FunctionEnd + +/** + * @brief show cma log dialogbox ig user has choosen to install cma +*/ +Function setup_log_show + ${If} ${SectionIsSelected} ${CMAInstSection} + Call fnc_log_dlg_Show + ${EndIf} +FunctionEnd + +/** + * @brief show cma encryption dialogbox ig user has choosen to install cma +*/ +Function setup_cma_encryption_show + ${If} ${SectionIsSelected} ${CMAInstSection} + Call fnc_encryption_Show + ${EndIf} +FunctionEnd + + +/** + * @brief uninstall section +*/ +Section "uninstall" UninstallSection + SetRegView 64 + # the only way to delete a service without reboot + ExecWait 'net stop ${SERVICE_NAME}' + ExecWait 'sc delete ${SERVICE_NAME}' + + delete $INSTDIR\centagent.exe + delete $INSTDIR\centreon-monitoring-agent-modify.exe + + #cma + DeleteRegKey HKLM "${CMA_REG_KEY}" + DeleteRegKey /ifempty HKLM "Software\Centreon" + + #event logger + DeleteRegKey HKLM "SYSTEM\CurrentControlSet\Services\EventLog\Application\${SERVICE_NAME}" + + # Always delete uninstaller as the last action + delete $INSTDIR\uninstall.exe + + # Try to remove the install directory - this will only happen if it is empty + rmDir $INSTDIR + rmDir "$PROGRAMFILES64\${COMPANYNAME}" + + DeleteRegKey HKLM "${UNINSTALL_KEY}" +SectionEnd + +/** + * @brief called on uninstall +*/ +function un.onInit + SetShellVarContext all + + ${If} ${Silent} + SetErrorLevel 0 + Call un.show_uninstaller_help + Call un.show_version + Call un.silent_verify_admin + + ClearErrors + ${GetOptions} $cmdline_parameters "--uninstall_plugins" $0 + ${IfNot} ${Errors} + rmDir /r ${PLUGINS_DIR} + ${EndIf} + + ClearErrors + ${GetOptions} $cmdline_parameters "--uninstall_cma" $0 + ${IfNot} ${Errors} + SectionSetFlags ${UninstallSection} ${SF_SELECTED} + ${Else} + SectionSetFlags ${UninstallSection} 0 + ${EndIf} + + ${Else} + !insertmacro verify_user_is_admin + + MessageBox MB_YESNO "Do you want to remove the Centreon plugins for the agents?" IDNO no_plugins_remove + rmDir /r ${PLUGINS_DIR} + no_plugins_remove: + + MessageBox MB_YESNO "Do you want to remove the Centreon Monitoring Agent?" IDYES no_cma_remove + Abort + no_cma_remove: + + ${EndIf} +functionEnd diff --git a/agent/installer/dlg_helper.nsi b/agent/installer/dlg_helper.nsi new file mode 100644 index 00000000000..c6a864426a9 --- /dev/null +++ b/agent/installer/dlg_helper.nsi @@ -0,0 +1,450 @@ +# +# Copyright 2024 Centreon +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# +# For more information : contact@centreon.com +# + +!include "NSISpcre.nsh" + +!insertmacro REMatches + + +/*************************************************************************************** + setup dialogbox +***************************************************************************************/ + +/** + * @brief initilalize controls with registry contents +*/ +Function init_setup_dlg + Push $0 + + SetRegView 64 + ReadRegStr $0 HKLM ${CMA_REG_KEY} "host" + ${If} $0 == "" + ReadRegStr $0 HKLM "System\CurrentControlSet\Control\ComputerName\ActiveComputerName" "ComputerName" + ${EndIf} + ${NSD_SetText} $hCtl_cma_host_name $0 + ReadRegStr $0 HKLM ${CMA_REG_KEY} "endpoint" + ${NSD_SetText} $hCtl_cma_endpoint $0 + ReadRegDWORD $0 HKLM ${CMA_REG_KEY} "reversed_grpc_streaming" + ${If} $0 > 0 + ${NSD_Check} $hCtl_cma_reverse + ${EndIf} + + Call reverse_onClick + + Pop $0 +FunctionEnd + +/** + * @brief validation handler +*/ +Function setup_dlg_onNext + Push $0 + Push $1 + Var /GLOBAL reversed_checked + ${NSD_GetState} $hCtl_cma_reverse $reversed_checked + + SetRegView 64 + ${NSD_GetText} $hCtl_cma_host_name $0 + ${If} $0 == "" + MessageBox MB_OK|MB_ICONSTOP "Empty host name not allowed" + Pop $1 + Pop $0 + Abort + ${EndIf} + + ${NSD_GetText} $hCtl_cma_endpoint $1 + ${If} $1 !~ "[a-zA-Z0-9\.\-_]+:[0-9]+" + ${If} $reversed_checked == ${BST_CHECKED} + MessageBox MB_OK|MB_ICONSTOP "The correct format for the listening interface is :." + ${Else} + MessageBox MB_OK|MB_ICONSTOP "The correct format for the endpoint is :." + ${EndIf} + Pop $1 + Pop $0 + Abort + ${EndIf} + + WriteRegStr HKLM ${CMA_REG_KEY} "host" "$0" + WriteRegStr HKLM ${CMA_REG_KEY} "endpoint" "$1" + + ${If} $reversed_checked == ${BST_CHECKED} + WriteRegDWORD HKLM ${CMA_REG_KEY} "reversed_grpc_streaming" 1 + ${Else} + WriteRegDWORD HKLM ${CMA_REG_KEY} "reversed_grpc_streaming" 0 + ${EndIf} + + Pop $1 + Pop $0 +FunctionEnd + +/** + * @brief Poller-initiated connection checkbox onClick handler +*/ +Function reverse_onClick + Push $0 + ${NSD_GetState} $hCtl_cma_reverse $0 + ${If} $0 == ${BST_CHECKED} + ${NSD_SetText} $hCtl_cma_endpoint_label "Listening interface:" + ${Else} + ${NSD_SetText} $hCtl_cma_endpoint_label "Poller endpoint:" + ${EndIf} + + Pop $0 +FunctionEnd + +/** + * @brief hostname I image onClick handler +*/ +Function hostname_help_onClick + MessageBox MB_ICONINFORMATION "The name of the host as defined in the Centreon interface." +FunctionEnd + +/** + * @brief endpoint I image onClick handler +*/ +Function endpoint_help_onClick + Push $0 + ${NSD_GetState} $hCtl_cma_reverse $0 + ${If} $0 == ${BST_CHECKED} + MessageBox MB_ICONINFORMATION "Interface and port on which the agent will accept connections from the poller. 0.0.0.0 means all interfaces." + ${Else} + MessageBox MB_ICONINFORMATION "IP address of DNS name of the poller the agent will connect to." + ${EndIf} + Pop $0 +FunctionEnd + +/** + * @brief Poller-initiated connection checkbox I image onClick handler +*/ +Function reverse_help_onClick + MessageBox MB_ICONINFORMATION "Use when the agent cannot connect to the poller directly: the poller will initiate the connection." +FunctionEnd + + +/*************************************************************************************** + log dialogbox +***************************************************************************************/ + +/** + * @brief initilalize controls with registry contents +*/ +Function init_log_dlg + Push $0 + + SetRegView 64 + ReadRegStr $0 HKLM ${CMA_REG_KEY} "log_file" + ${If} $0 != "" + ${NSD_SetText} $hCtl_log_dlg_log_file_Txt $0 + ${EndIf} + ReadRegStr $0 HKLM ${CMA_REG_KEY} "log_level" + ${If} $0 == "" + StrCpy $0 "error" + ${EndIf} + ${NSD_CB_SelectString} $hCtl_log_dlg_log_level $0 + ReadRegStr $0 HKLM ${CMA_REG_KEY} "log_type" + ${If} $0 == "" + StrCpy $0 "EventLog" + ${EndIf} + ${NSD_CB_SelectString} $hCtl_log_dlg_log_type $0 + ReadRegDWORD $0 HKLM ${CMA_REG_KEY} "log_max_file_size" + ${If} $0 > 0 + ${NSD_SetText} $hCtl_log_dlg_max_file_size $0 + ${EndIf} + ReadRegDWORD $0 HKLM ${CMA_REG_KEY} "log_max_files" + ${If} $0 > 0 + ${NSD_SetText} $hCtl_log_dlg_max_files $0 + ${EndIf} + + Pop $0 +FunctionEnd + + +/** + * @brief validation handler +*/ +Function log_dlg_onNext + Push $0 + + SetRegView 64 + ${NSD_GetText} $hCtl_log_dlg_log_level $0 + ${If} $0 != "" + ${StrCase} $0 $0 "L" + WriteRegStr HKLM ${CMA_REG_KEY} "log_level" "$0" + ${EndIf} + + ${NSD_GetText} $hCtl_log_dlg_log_type $0 + ${If} $0 == "" + Pop $0 + Return + ${EndIf} + + ${If} $0 == "File" + ${NSD_GetText} $hCtl_log_dlg_log_file_Txt $0 + Push $1 + StrCpy $1 ${FILE_PATH_REGEXP} + ${If} $0 !~ $1 + MessageBox MB_OK|MB_ICONSTOP "Bad log file path" + Pop $1 + Pop $0 + Abort + ${EndIf} + Pop $1 + WriteRegStr HKLM ${CMA_REG_KEY} "log_type" "file" + WriteRegStr HKLM ${CMA_REG_KEY} "log_file" $0 + ${NSD_GetText} $hCtl_log_dlg_max_file_size $0 + WriteRegDWORD HKLM ${CMA_REG_KEY} "log_max_file_size" $0 + ${NSD_GetText} $hCtl_log_dlg_max_files $0 + WriteRegDWORD HKLM ${CMA_REG_KEY} "log_max_files" $0 + ${Else} + ${StrCase} $0 $0 "L" + WriteRegStr HKLM ${CMA_REG_KEY} "log_type" "event-log" + ${EndIf} + + Pop $0 + +FunctionEnd + +/** + * @brief when user choose log to file or log to EventLogger, file control group is hidden or shown +*/ +Function on_log_type_changed + ${NSD_GetText} $hCtl_log_dlg_log_type $0 + + ${If} $0 == "File" + ShowWindow $hCtl_log_dlg_file_group ${SW_SHOW} + ShowWindow $hCtl_log_dlg_label_max_files ${SW_SHOW} + ShowWindow $hCtl_log_dlg_max_files ${SW_SHOW} + ShowWindow $hCtl_log_dlg_max_file_size ${SW_SHOW} + ShowWindow $hCtl_log_dlg_label_max_file_size ${SW_SHOW} + ShowWindow $hCtl_log_dlg_label_log_file ${SW_SHOW} + ShowWindow $hCtl_log_dlg_log_file_Txt ${SW_SHOW} + ShowWindow $hCtl_log_dlg_log_file_Btn ${SW_SHOW} + ShowWindow $hCtl_log_dlg_max_files_help ${SW_SHOW} + ShowWindow $hCtl_log_dlg_max_file_size_help ${SW_SHOW} + ${Else} + ShowWindow $hCtl_log_dlg_file_group ${SW_HIDE} + ShowWindow $hCtl_log_dlg_label_max_files ${SW_HIDE} + ShowWindow $hCtl_log_dlg_max_files ${SW_HIDE} + ShowWindow $hCtl_log_dlg_max_file_size ${SW_HIDE} + ShowWindow $hCtl_log_dlg_label_max_file_size ${SW_HIDE} + ShowWindow $hCtl_log_dlg_label_log_file ${SW_HIDE} + ShowWindow $hCtl_log_dlg_log_file_Txt ${SW_HIDE} + ShowWindow $hCtl_log_dlg_log_file_Btn ${SW_HIDE} + ShowWindow $hCtl_log_dlg_max_files_help ${SW_HIDE} + ShowWindow $hCtl_log_dlg_max_file_size_help ${SW_HIDE} + ${EndIf} + +FunctionEnd + +/** + * @brief max file I image onClick handler +*/ +Function max_files_help_onClick + MessageBox MB_ICONINFORMATION "For the rotation of logs to be active, it is necessary that both parameters 'Max File Size' and 'Max number of files' are set. The space used by the logs of the agent will not exceed 'Max File Size' * 'Max number of files'." +FunctionEnd + +/** + * @brief max file size I image onClick handler +*/ +Function max_file_size_help_onClick + MessageBox MB_ICONINFORMATION "For the rotation of logs to be active, it is necessary that both parameters 'Max File Size' and 'Max number of files' are set. The space used by the logs of the agent will not exceed 'Max File Size' * 'Max number of files'." +FunctionEnd + + + +/*************************************************************************************** + encryption dialogbox +***************************************************************************************/ + +/** + * @brief initilalize controls with registry contents +*/ +Function init_encryption_dlg + Push $0 + + SetRegView 64 + ClearErrors + ReadRegDWORD $0 HKLM ${CMA_REG_KEY} "encryption" + ${If} ${Errors} + ${OrIf} $0 > 0 + ${NSD_Check} $hCtl_encryption_EncryptionCheckBox + ${EndIf} + ReadRegStr $0 HKLM ${CMA_REG_KEY} "certificate" + ${NSD_SetText} $hCtl_encryption_certificate_file_Txt $0 + ReadRegStr $0 HKLM ${CMA_REG_KEY} "private_key" + ${NSD_SetText} $hCtl_encryption_private_key_file_Txt $0 + ReadRegStr $0 HKLM ${CMA_REG_KEY} "ca_certificate" + ${NSD_SetText} $hCtl_encryption_ca_file_Txt $0 + ReadRegStr $0 HKLM ${CMA_REG_KEY} "ca_name" + ${NSD_SetText} $hCtl_encryption_ca_name $0 + + Pop $0 +FunctionEnd + + +/** + * @brief validation handler +*/ +Function encryption_dlg_onNext + Push $0 + Push $1 + Var /GLOBAL reverse_connection + + ReadRegDWORD $reverse_connection HKLM ${CMA_REG_KEY} "reversed_grpc_streaming" + + + StrCpy $0 ${FILE_PATH_REGEXP} + + ${NSD_GetState} $hCtl_encryption_EncryptionCheckBox $1 + ${If} $1 == ${BST_CHECKED} + WriteRegDWORD HKLM ${CMA_REG_KEY} "encryption" 1 + + ${NSD_GetText} $hCtl_encryption_certificate_file_Txt $1 + ${If} $1 == "" + ${If} $reverse_connection > 0 + MessageBox MB_OK|MB_ICONSTOP "If encryption and poller-initiated connection are active, the certificate is mandatory." + Pop $1 + Pop $0 + Abort + ${EndIf} + ${Else} + ${If} $1 !~ $0 + MessageBox MB_OK|MB_ICONSTOP "Bad certificate file path." + Pop $1 + Pop $0 + Abort + ${EndIf} + ${EndIf} + Push $2 + ${NSD_GetText} $hCtl_encryption_private_key_file_Txt $2 + ${If} $2 == "" + ${If} $reverse_connection > 0 + MessageBox MB_OK|MB_ICONSTOP "If encryption and poller-initiated connection are active, the private key is mandatory." + Pop $2 + Pop $1 + Pop $0 + Abort + ${EndIf} + ${Else} + ${If} $2 !~ $0 + MessageBox MB_OK|MB_ICONSTOP "Bad private key file path." + Pop $2 + Pop $1 + Pop $0 + Abort + ${EndIf} + ${EndIf} + Push $3 + ${NSD_GetText} $hCtl_encryption_ca_file_Txt $3 + ${If} $3 != "" + ${AndIf} $3 !~ $0 + MessageBox MB_OK|MB_ICONSTOP "Bad CA file path." + Pop $3 + Pop $2 + Pop $1 + Pop $0 + Abort + ${EndIf} + + WriteRegStr HKLM ${CMA_REG_KEY} "certificate" $1 + WriteRegStr HKLM ${CMA_REG_KEY} "private_key" $2 + WriteRegStr HKLM ${CMA_REG_KEY} "ca_certificate" $3 + ${NSD_GetText} $hCtl_encryption_ca_name $1 + WriteRegStr HKLM ${CMA_REG_KEY} "ca_name" $1 + Pop $3 + Pop $2 + ${Else} + WriteRegDWORD HKLM ${CMA_REG_KEY} "encryption" 0 + ${EndIf} + + Pop $1 + Pop $0 +FunctionEnd + +/** + * @brief when encryption checkbox is checked or not, encryption group is shown or hidden +*/ +Function on_encryptioncheckbox_click + Push $0 + ${NSD_GetState} $hCtl_encryption_EncryptionCheckBox $0 + ${If} $0 == ${BST_CHECKED} + ShowWindow $hCtl_encryption_EncryptionGroupBox ${SW_SHOW} + ShowWindow $hCtl_encryption_label_private_key_file ${SW_SHOW} + ShowWindow $hCtl_encryption_private_key_file_Txt ${SW_SHOW} + ShowWindow $hCtl_encryption_private_key_file_Btn ${SW_SHOW} + ShowWindow $hCtl_encryption_label_certificate_file ${SW_SHOW} + ShowWindow $hCtl_encryption_certificate_file_Txt ${SW_SHOW} + ShowWindow $hCtl_encryption_certificate_file_Btn ${SW_SHOW} + ShowWindow $hCtl_encryption_label_ca_file ${SW_SHOW} + ShowWindow $hCtl_encryption_ca_file_Txt ${SW_SHOW} + ShowWindow $hCtl_encryption_ca_file_Btn ${SW_SHOW} + ShowWindow $hCtl_encryption_label_ca_name ${SW_SHOW} + ShowWindow $hCtl_encryption_ca_name ${SW_SHOW} + ShowWindow $hCtl_encryption_ca_name_help ${SW_SHOW} + ShowWindow $hCtl_encryption_ca_file_help ${SW_SHOW} + ShowWindow $hCtl_encryption_certificate_file_help ${SW_SHOW} + ShowWindow $hCtl_encryption_private_key_file_help ${SW_SHOW} + ${Else} + ShowWindow $hCtl_encryption_EncryptionGroupBox ${SW_HIDE} + ShowWindow $hCtl_encryption_label_private_key_file ${SW_HIDE} + ShowWindow $hCtl_encryption_private_key_file_Txt ${SW_HIDE} + ShowWindow $hCtl_encryption_private_key_file_Btn ${SW_HIDE} + ShowWindow $hCtl_encryption_label_certificate_file ${SW_HIDE} + ShowWindow $hCtl_encryption_certificate_file_Txt ${SW_HIDE} + ShowWindow $hCtl_encryption_certificate_file_Btn ${SW_HIDE} + ShowWindow $hCtl_encryption_label_ca_file ${SW_HIDE} + ShowWindow $hCtl_encryption_ca_file_Txt ${SW_HIDE} + ShowWindow $hCtl_encryption_ca_file_Btn ${SW_HIDE} + ShowWindow $hCtl_encryption_label_ca_name ${SW_HIDE} + ShowWindow $hCtl_encryption_ca_name ${SW_HIDE} + ShowWindow $hCtl_encryption_ca_name_help ${SW_HIDE} + ShowWindow $hCtl_encryption_ca_file_help ${SW_HIDE} + ShowWindow $hCtl_encryption_certificate_file_help ${SW_HIDE} + ShowWindow $hCtl_encryption_private_key_file_help ${SW_HIDE} + ${EndIf} + Pop $0 +FunctionEnd + + +/** + * @brief private key file I image onClick handler +*/ +Function private_key_file_help_onClick + MessageBox MB_ICONINFORMATION "Private key file path. Mandatory if encryption and poller-initiated connection are active." +FunctionEnd + +/** + * @brief certificate file I image onClick handler +*/ +Function certificate_file_help_onClick + MessageBox MB_ICONINFORMATION "Public certificate file path. Mandatory if encryption and poller-initiated connection are active." +FunctionEnd + +/** + * @brief ca file I image onClick handler +*/ +Function ca_file_help_onClick + MessageBox MB_ICONINFORMATION "Trusted CA's certificate." +FunctionEnd + +/** + * @brief ca name I image onClick handler +*/ +Function ca_name_help_onClick + MessageBox MB_ICONINFORMATION "Expected TLS certificate common name (CN) - leave blank if unsure." +FunctionEnd diff --git a/agent/installer/inetc/Contrib/Inetc/afxres.h b/agent/installer/inetc/Contrib/Inetc/afxres.h new file mode 100644 index 00000000000..4719049d181 --- /dev/null +++ b/agent/installer/inetc/Contrib/Inetc/afxres.h @@ -0,0 +1,2 @@ +#include +#define IDC_STATIC (-1) diff --git a/agent/installer/inetc/Contrib/Inetc/api.h b/agent/installer/inetc/Contrib/Inetc/api.h new file mode 100644 index 00000000000..77b1b5ea002 --- /dev/null +++ b/agent/installer/inetc/Contrib/Inetc/api.h @@ -0,0 +1,83 @@ +/* + * apih + * + * This file is a part of NSIS. + * + * Copyright (C) 1999-2013 Nullsoft and Contributors + * + * Licensed under the zlib/libpng license (the "License"); + * you may not use this file except in compliance with the License. + * + * Licence details can be found in the file COPYING. + * + * This software is provided 'as-is', without any express or implied + * warranty. + */ + +#ifndef _NSIS_EXEHEAD_API_H_ +#define _NSIS_EXEHEAD_API_H_ + +// Starting with NSIS 2.42, you can check the version of the plugin API in exec_flags->plugin_api_version +// The format is 0xXXXXYYYY where X is the major version and Y is the minor version (MAKELONG(y,x)) +// When doing version checks, always remember to use >=, ex: if (pX->exec_flags->plugin_api_version >= NSISPIAPIVER_1_0) {} + +#define NSISPIAPIVER_1_0 0x00010000 +#define NSISPIAPIVER_CURR NSISPIAPIVER_1_0 + +// NSIS Plug-In Callback Messages +enum NSPIM +{ + NSPIM_UNLOAD, // This is the last message a plugin gets, do final cleanup + NSPIM_GUIUNLOAD, // Called after .onGUIEnd +}; + +// Prototype for callbacks registered with extra_parameters->RegisterPluginCallback() +// Return NULL for unknown messages +// Should always be __cdecl for future expansion possibilities +typedef UINT_PTR (*NSISPLUGINCALLBACK)(enum NSPIM); + +// extra_parameters data structures containing other interesting stuff +// but the stack, variables and HWND passed on to plug-ins. +typedef struct +{ + int autoclose; + int all_user_var; + int exec_error; + int abort; + int exec_reboot; // NSIS_SUPPORT_REBOOT + int reboot_called; // NSIS_SUPPORT_REBOOT + int XXX_cur_insttype; // depreacted + int plugin_api_version; // see NSISPIAPIVER_CURR + // used to be XXX_insttype_changed + int silent; // NSIS_CONFIG_SILENT_SUPPORT + int instdir_error; + int rtl; + int errlvl; + int alter_reg_view; + int status_update; +} exec_flags_t; + +#ifndef NSISCALL +# define NSISCALL __stdcall +#endif + +typedef struct { + exec_flags_t *exec_flags; + int (NSISCALL *ExecuteCodeSegment)(int, HWND); + void (NSISCALL *validate_filename)(LPTSTR); + int (NSISCALL *RegisterPluginCallback)(HMODULE, NSISPLUGINCALLBACK); // returns 0 on success, 1 if already registered and < 0 on errors +} extra_parameters; + +// Definitions for page showing plug-ins +// See Ui.c to understand better how they're used + +// sent to the outer window to tell it to go to the next inner window +#define WM_NOTIFY_OUTER_NEXT (WM_USER+0x8) + +// custom pages should send this message to let NSIS know they're ready +#define WM_NOTIFY_CUSTOM_READY (WM_USER+0xd) + +// sent as wParam with WM_NOTIFY_OUTER_NEXT when user cancels - heed its warning +#define NOTIFY_BYE_BYE 'x' + +#endif /* _PLUGIN_H_ */ diff --git a/agent/installer/inetc/Contrib/Inetc/crt.cpp b/agent/installer/inetc/Contrib/Inetc/crt.cpp new file mode 100644 index 00000000000..6ac8d818158 --- /dev/null +++ b/agent/installer/inetc/Contrib/Inetc/crt.cpp @@ -0,0 +1,105 @@ +#include + +#if defined(_MSC_VER) && _MSC_VER+0 >= 1400 +#if defined(_MSC_FULL_VER) && _MSC_FULL_VER+0 >= 140050727 +#include +#else +EXTERN_C void __stosb(BYTE*,BYTE,size_t); +#endif +#pragma intrinsic(__stosb) +#define CRTINTRINSIC_memset(p,c,s) __stosb((BYTE*)(p),(BYTE)(c),(s)) +#endif + +extern "C" void* __cdecl memset(void *p, int c, size_t z) +{ +#ifdef CRTINTRINSIC_memset + CRTINTRINSIC_memset(p, c, z); +#else + BYTE *pb = reinterpret_cast(p); + for(size_t i=0; istring_size) +* HTTP POST added +* Jun 06, 2005 IDOK on "Enter" key locked +* POST HTTP header added +* Jun 22, 2005 non-interaptable mode /nocancel +* and direct connect /noproxy +* Jun 29, 2005 post.php written and tested +* Jul 05, 2005 60 sec delay on WinInet detach problem +* solved (not fine, but works including +* installer exit and system reboot) +* Jul 08, 2005 'set foreground' finally removed +* Jul 26, 2005 POPUP translate option +* Aug 23, 2005 https service type in InternetConnect +* and "ignore certificate" flags +* Sep 30, 2005 https with bad certificate from old OS; +* Forbidden handling +* Dec 23, 2005 'put' entry point, new names, 12003 +* ftp error handling (on ftp write permission) +* 405 http error (method not allowed) +* Mar 12, 2006 Internal authorization via InternetErrorDlg() +* and Unauthorized (401) handling. +* Jun 10, 2006 Caption text option for Resume download +* MessageBox +* Jun 24, 2006 HEAD method, silent mode clean up +* Sep 05, 2006 Center dialog code from Backland +* Sep 07, 2006 NSISdl crash fix /Backland idea/ +* Sep 08, 2006 POST as dll entry point. +* Sep 21, 2006 parent dlg progr.bar style and font, +* nocancel via ws_sysmenu +* Sep 22, 2006 current lang IDCANCEL text, /canceltext +* and /useragent options +* Sep 24, 2006 .onInit improvements and defaults +* Nov 11, 2006 FTP path creation, root|current dir mgmt +* Jan 01, 2007 Global char[] cleanup, GetLastError() to +* status string on ERR_DIALOG, few MSVCRT replaces +* Jan 13, 2007 /HEADER option added +* Jan 28, 2007 _open -> CreateFile and related +* Feb 18, 2007 Speed calculating improved (pauses), +* /popup text parameter to hide URL +* Jun 07, 2007 Local file truncation added for download +* (CREATE_ALWAYS) +* Jun 11, 2007 FTP download permitted even if server rejects +* SIZE request (ProFTPD). +* Aug 11, 2007 Backland' fix for progress bar redraw/style +* issue in NSISdl display mode. +* Jan 09, 2008 {_trueparuex^}' fix - InternetSetFilePointer() +* returns -1 on error. +* /question option added for cancel question. +* Feb 15, 2008 PUT content-length file size fix +* Feb 17, 2008 char -> TCHAR replace for UNICODE option +* Feb 19, 2008 janekschwarz fix for HTTP PUT with auth +* CreateFile INVALID_HANDLE_VALUE on error fix +* Feb 20, 2008 base64 encoder update for unicode +* Feb 27, 2008 Unicode configurations added to VS 6 dsp +* Mar 20, 2008 HTTP PUT with proxy auth finally fixed +* FTP errors handling improved. +* HEAD bug fixed +* Mar 27, 2008 Details window hide/show in NSISdl mode +* Apr 10, 2008 Auth test method changed to HEAD for +* old proxy's +* Apr 30, 2008 InternetErrorDlg() ERROR_SUCESS on cancel +* click patched +* 3xx errors added to status list. +* May 20, 2008 InternetReadFile on cable disconnect patched +* May 20, 2008 Reply status "0" patch (name resolution?) +* Jul 15, 2008 HTTP 304 parsing. Incorrect size reported fix. +* Aug 21, 2009 Escape sequence convertion removed (caused +* error in signature with %2b requests) +* Marqueue progess bar style for unknown file size. +* Feb 04, 2010 Unicode POST patch - body converted to multibyte +* Jul 11, 2010 /FILE POST option added +* Nov 04, 2010 Disabled cookies and cache for cleanliness +* Feb 14, 2011 Fixed reget bug introduced in previous commit +* Feb 18, 2011 /NOCOOKIES option added +* Mar 02, 2011 User-agent buffer increased. Small memory leak fix +* Mar 23, 2011 Use caption on embedded progressbar - zenpoy +* Apr 05, 2011 reget fix - INTERNET_FLAG_RELOAD for first connect only +* Apr 27, 2011 /receivetimeout option added for big files and antivirus +* Jun 15, 2011 Stack clean up fix on cancel - zenpoy +* Oct 19, 2011 FTP PUT error parsing fix - tperquin +* Aug 19, 2013 Fix focus stealing when in silent - negativesir, JohnTHaller +* Jul 20, 2014 - 1.0.4.4 - Stuart 'Afrow UK' Welch +* /tostack & /tostackconv added +* Version information resource added +* Updated to NSIS 3.0 plugin API +* Upgraded to Visual Studio 2012 +* 64-bit build added +* MSVCRT dependency removed +* Sep 04, 2015 - 1.0.5.0 - anders_k +* HTTPS connections are more secure by default +* Added /weaksecurity switch, reverts to old cert. security checks +* Sep 06, 2015 - 1.0.5.1 - anders_k +* Don't allow infinite FtpCreateDirectory tries +* Use memset intrinsic when possible to avoid VC code generation bug +* Oct 17, 2015 - 1.0.5.2 - anders_k +* Tries to set FTP mode to binary before querying the size. +* Calls FtpGetFileSize if it exists. +* Sep 24, 2018 - 1.0.5.3 - anders_k +* /tostackconv supports UTF-8 and UTF-16LE BOM sniffing and conversion. +*******************************************************/ + + +#define _WIN32_WINNT 0x0500 + +#include +//#include +#include +#include +#include "pluginapi.h" +#include "resource.h" + +#include // strstr etc + +#ifndef PBM_SETMARQUEE +#define PBM_SETMARQUEE (WM_USER + 10) +#define PBS_MARQUEE 0x08 +#endif +#ifndef HTTP_QUERY_PROXY_AUTHORIZATION +#define HTTP_QUERY_PROXY_AUTHORIZATION 61 +#endif +#ifndef SECURITY_FLAG_IGNORE_REVOCATION +#define SECURITY_FLAG_IGNORE_REVOCATION 0x00000080 +#endif +#ifndef SECURITY_FLAG_IGNORE_UNKNOWN_CA +#define SECURITY_FLAG_IGNORE_UNKNOWN_CA 0x00000100 +#endif + +// IE 4 safety and VS 6 compatibility +typedef BOOL (__stdcall *FTP_CMD)(HINTERNET,BOOL,DWORD,LPCTSTR,DWORD,HINTERNET *); +FTP_CMD myFtpCommand; + +#define PLUGIN_NAME TEXT("Inetc plug-in") +#define INETC_USERAGENT TEXT("NSIS_Inetc (Mozilla)") +#define PB_RANGE 400 // progress bar values range +#define PAUSE1_SEC 2 // transfer error indication time, for reget only +#define PAUSE2_SEC 3 // paused state time, increase this if need (60?) +#define PAUSE3_SEC 1 // pause after resume button pressed +#define NOT_AVAILABLE 0xffffffff +#define POST_HEADER TEXT("Content-Type: application/x-www-form-urlencoded") +#define PUT_HEADER TEXT("Content-Type: octet-stream\nContent-Length: %d") +#define INTERNAL_OK 0xFFEE +#define PROGRESS_MS 1000 // screen values update interval +#define DEF_QUESTION TEXT("Are you sure that you want to stop download?") +#define HOST_AUTH_HDR TEXT("Authorization: basic %s") +#define PROXY_AUTH_HDR TEXT("Proxy-authorization: basic %s") + +//#define MY_WEAKSECURITY_CERT_FLAGS SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_REVOCATION | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID | SECURITY_FLAG_IGNORE_CERT_CN_INVALID +#define MY_WEAKSECURITY_CERT_FLAGS SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_REVOCATION +#define MY_REDIR_FLAGS INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP | INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS +#define MY_HTTPS_FLAGS (MY_REDIR_FLAGS | INTERNET_FLAG_SECURE) + +enum STATUS_CODES { + ST_OK = 0, + ST_CONNECTING, + ST_DOWNLOAD, + ST_CANCELLED, + ST_URLOPEN, + // ST_OPENING, + ST_PAUSE, + ERR_TERMINATED, + ERR_DIALOG, + ERR_INETOPEN, + ERR_URLOPEN, + ERR_TRANSFER, + ERR_FILEOPEN, + ERR_FILEWRITE, + ERR_FILEREAD, + ERR_REGET, + ERR_CONNECT, + ERR_OPENREQUEST, + ERR_SENDREQUEST, + ERR_CRACKURL, + ERR_NOTFOUND, + ERR_THREAD, + ERR_PROXY, + ERR_FORBIDDEN, + ERR_NOTALLOWED, + ERR_REQUEST, + ERR_SERVER, + ERR_AUTH, + ERR_CREATEDIR, + ERR_PATH, + ERR_NOTMODIFIED, + ERR_REDIRECTION +}; + + +static TCHAR szStatus[][32] = { + TEXT("OK"),TEXT("Connecting"),TEXT("Downloading"),TEXT("Cancelled"),TEXT("Connecting"), //TEXT("Opening URL")), + TEXT("Reconnect Pause"),TEXT("Terminated"),TEXT("Dialog Error"),TEXT("Open Internet Error"), + TEXT("Open URL Error"),TEXT("Transfer Error"),TEXT("File Open Error"),TEXT("File Write Error"),TEXT("File Read Error"), + TEXT("Reget Error"),TEXT("Connection Error"),TEXT("OpenRequest Error"),TEXT("SendRequest Error"), + TEXT("URL Parts Error"),TEXT("File Not Found (404)"),TEXT("CreateThread Error"),TEXT("Proxy Error (407)"), + TEXT("Access Forbidden (403)"),TEXT("Not Allowed (405)"),TEXT("Request Error"),TEXT("Server Error"), + TEXT("Unauthorized (401)"),TEXT("FtpCreateDir failed (550)"),TEXT("Error FTP path (550)"),TEXT("Not Modified"), + TEXT("Redirection") +}; + +HINSTANCE g_hInstance; +TCHAR fn[MAX_PATH]=TEXT(""), +*url = NULL, +*szAlias = NULL, +*szProxy = NULL, +*szHeader = NULL, +*szBanner = NULL, +*szQuestion = NULL, +szCancel[64]=TEXT(""), +szCaption[128]=TEXT(""), +szUserAgent[256]=TEXT(""), +szResume[256] = TEXT("Your internet connection seems to be not permitted or dropped out!\nPlease reconnect and click Retry to resume installation."); +CHAR *szPost = NULL, +post_fname[MAX_PATH] = ""; +DWORD fSize = 0; +TCHAR *szToStack = NULL; + +int status; +DWORD cnt = 0, +cntToStack = 0, +fs = 0, +timeout = 0, +receivetimeout = 0; +DWORD startTime, transfStart, openType; +bool silent, popup, resume, nocancel, noproxy, nocookies, convToStack, g_ignorecertissues; + +HWND childwnd; +HWND hDlg; +bool fput = false, fhead = false; + + +#define Option_IgnoreCertIssues() ( g_ignorecertissues ) + +static FARPROC GetWininetProcAddress(LPCSTR Name) +{ + return GetProcAddress(LoadLibraryA("WININET"), Name); +} + +/***************************************************** +* FUNCTION NAME: sf(HWND) +* PURPOSE: +* moves HWND to top and activates it +* SPECIAL CONSIDERATIONS: +* commented because annoying +*****************************************************/ +/* +void sf(HWND hw) +{ +DWORD ctid = GetCurrentThreadId(); +DWORD ftid = GetWindowThreadProcessId(GetForegroundWindow(), NULL); +AttachThreadInput(ftid, ctid, TRUE); +SetForegroundWindow(hw); +AttachThreadInput(ftid, ctid, FALSE); +} +*/ + +static TCHAR szUrl[64] = TEXT(""); +static TCHAR szDownloading[64] = TEXT("Downloading %s"); +static TCHAR szConnecting[64] = TEXT("Connecting ..."); +static TCHAR szSecond[64] = TEXT("second"); +static TCHAR szMinute[32] = TEXT("minute"); +static TCHAR szHour[32] = TEXT("hour"); +static TCHAR szPlural[32] = TEXT("s"); +static TCHAR szProgress[128] = TEXT("%dkB (%d%%) of %dkB @ %d.%01dkB/s"); +static TCHAR szRemaining[64] = TEXT(" (%d %s%s remaining)"); +static TCHAR szBasic[128] = TEXT(""); +static TCHAR szAuth[128] = TEXT(""); + +// is it possible to make it working with unicode strings? + +/* Base64 encode one byte */ +static TCHAR encode(unsigned char u) { + + if(u < 26) return TEXT('A')+u; + if(u < 52) return TEXT('a')+(u-26); + if(u < 62) return TEXT('0')+(u-52); + if(u == 62) return TEXT('+'); + return TEXT('/'); +} + +TCHAR *encode_base64(int size, TCHAR *src, TCHAR *dst) { + + int i; + TCHAR *p; + + if(!src) + return NULL; + + if(!size) + size= lstrlen(src); + + p = dst; + + for(i=0; i>2; + b5= ((b1&0x3)<<4)|(b2>>4); + b6= ((b2&0xf)<<2)|(b3>>6); + b7= b3&0x3f; + + *p++= encode(b4); + *p++= encode(b5); + + if(i+1 0) + { + dw = data_buf; + if(!InternetWriteFile(hFile, dw, bytesDone, &rslt) || rslt == 0) + { + status = ERR_TRANSFER; + break; + } + dw += rslt; + cnt += rslt; + bytesDone -= rslt; + } + } + else + { + if(!InternetReadFile(hFile, data_buf, sizeof(data_buf), &rslt)) + { + status = ERR_TRANSFER; + break; + } + if(rslt == 0) // EOF reached or cable disconnect + { +// on cable disconnect returns TRUE and 0 bytes. is cnt == 0 OK (zero file size)? +// cannot check this if reply is chunked (no content-length, http 1.1) + status = (fs != NOT_AVAILABLE && cnt < fs) ? ERR_TRANSFER : ST_OK; + break; + } + if(szToStack) + { + for (DWORD i = 0; cntToStack < g_stringsize && i < rslt; i++, cntToStack++) + if (convToStack) + *((BYTE*)szToStack + cntToStack) = data_buf[i]; // Bytes + else + *(szToStack + cntToStack) = data_buf[i]; // ? to TCHARs + } + else if(!WriteFile(localFile, data_buf, rslt, &bytesDone, NULL) || + rslt != bytesDone) + { + status = ERR_FILEWRITE; + break; + } + cnt += rslt; + } + } +} + +/***************************************************** +* FUNCTION NAME: mySendRequest() +* PURPOSE: +* HttpSendRequestEx() sends headers only - for PUT +* We also can use InetWriteFile for POST body I guess +* SPECIAL CONSIDERATIONS: +* +*****************************************************/ +int mySendRequest(HINTERNET hFile) +{ + INTERNET_BUFFERS BufferIn = {0}; + if(fput) + { + BufferIn.dwStructSize = sizeof( INTERNET_BUFFERS ); + BufferIn.dwBufferTotal = fs; + return HttpSendRequestEx( hFile, &BufferIn, NULL, HSR_INITIATE, 0); + } + return HttpSendRequest(hFile, NULL, 0, szPost, fSize); +} + +/***************************************************** +* FUNCTION NAME: queryStatus() +* PURPOSE: +* http status code comes before download (get) and +* after upload (put), so this is called from 2 places +* SPECIAL CONSIDERATIONS: +* +*****************************************************/ +bool queryStatus(HINTERNET hFile) +{ + TCHAR buf[256] = TEXT(""); + DWORD rslt; + if(HttpQueryInfo(hFile, HTTP_QUERY_STATUS_CODE, + buf, &(rslt = sizeof(buf)), NULL)) + { + buf[3] = 0; + if(lstrcmp(buf, TEXT("0")) == 0 || *buf == 0) + status = ERR_SENDREQUEST; + else if(lstrcmp(buf, TEXT("401")) == 0) + status = ERR_AUTH; + else if(lstrcmp(buf, TEXT("403")) == 0) + status = ERR_FORBIDDEN; + else if(lstrcmp(buf, TEXT("404")) == 0) + status = ERR_NOTFOUND; + else if(lstrcmp(buf, TEXT("407")) == 0) + status = ERR_PROXY; + else if(lstrcmp(buf, TEXT("405")) == 0) + status = ERR_NOTALLOWED; + else if(lstrcmp(buf, TEXT("304")) == 0) + status = ERR_NOTMODIFIED; + else if(*buf == TEXT('3')) + { + status = ERR_REDIRECTION; + wsprintf(szStatus[status] + lstrlen(szStatus[status]), TEXT(" (%s)"), buf); + } + else if(*buf == TEXT('4')) + { + status = ERR_REQUEST; + wsprintf(szStatus[status] + lstrlen(szStatus[status]), TEXT(" (%s)"), buf); + } + else if(*buf == TEXT('5')) + { + status = ERR_SERVER; + wsprintf(szStatus[status] + lstrlen(szStatus[status]), TEXT(" (%s)"), buf); + } + return true; + } + return false; +} + +/***************************************************** +* FUNCTION NAME: openFtpFile() +* PURPOSE: +* control connection, size request, re-get lseek +* SPECIAL CONSIDERATIONS: +* +*****************************************************/ +HINTERNET openFtpFile(HINTERNET hConn, + TCHAR *path) +{ + TCHAR buf[256] = TEXT(""), *movp; + HINTERNET hFile; + DWORD rslt, err, gle; + bool https_req_ok = false; + + /* reads connection / auth responce info and cleares 'control' buffer this way */ + InternetGetLastResponseInfo(&err, buf, &(rslt = sizeof(buf))); + if(cnt == 0) + { + if(!fput) // we know local file size already + { + if (myFtpCommand) + { + /* Try to set the REPRESENTATION TYPE to I[mage] (Binary) because some servers + don't accept the SIZE command in ASCII mode */ + myFtpCommand(hConn, false, FTP_TRANSFER_TYPE_ASCII, TEXT("TYPE I"), 0, &hFile); + } + /* too clever myFtpCommand returnes false on the valid TEXT("550 Not found/Not permitted" server answer, + to read answer I had to ignory returned false (!= 999999) :-( + GetLastError also possible, but MSDN description of codes is very limited */ + wsprintf(buf, TEXT("SIZE %s"), path + 1); + if(myFtpCommand != NULL && + myFtpCommand(hConn, false, FTP_TRANSFER_TYPE_ASCII, buf, 0, &hFile) != 9999 && + memset(buf, 0, sizeof(buf)) != NULL && + InternetGetLastResponseInfo(&err, buf, &(rslt = sizeof(buf)))) + { + if(_tcsstr(buf, TEXT("213 "))) + { + fs = myatou(_tcschr(buf, TEXT(' ')) + 1); + } + /* stupid ProFTPD returns error on SIZE request. let's continue without size. + But IE knows some trick to get size from ProFTPD...... + else if(mystrstr(buf, TEXT("550 TEXT(")) + { + status = ERR_SIZE_NOT_PERMITTED; + return NULL; + } + */ + } + if(fs == 0) + { + fs = NOT_AVAILABLE; + } + } + } + else + { + wsprintf(buf, TEXT("REST %d"), cnt); + if(myFtpCommand == NULL || + !myFtpCommand(hConn, false, FTP_TRANSFER_TYPE_BINARY, buf, 0, &hFile) || + memset(buf, 0, sizeof(buf)) == NULL || + !InternetGetLastResponseInfo(&err, buf, &(rslt = sizeof(buf))) || + (_tcsstr(buf, TEXT("350")) == NULL && _tcsstr(buf, TEXT("110")) == NULL)) + { + status = ERR_REGET; + return NULL; + } + } + if((hFile = FtpOpenFile(hConn, path + 1, fput ? GENERIC_WRITE : GENERIC_READ, + FTP_TRANSFER_TYPE_BINARY|INTERNET_FLAG_RELOAD,0)) == NULL) + { + gle = GetLastError(); + *buf = 0; + InternetGetLastResponseInfo(&err, buf, &(rslt = sizeof(buf))); + // wrong path - dir may not exist or upload may be not allowed + // we use ftp://host//path (double /) to define path from FS root + if(fput && (_tcsstr(buf, TEXT("550")) != NULL || _tcsstr(buf, TEXT("553")) != NULL)) + { + movp = path + 1; + if(*movp == TEXT('/')) movp++; // don't need to create root + for (UINT8 escapehatch = 0; ++escapehatch;) // Weak workaround for http://forums.winamp.com/showpost.php?p=3031692&postcount=513 bug + { + TCHAR *pbs = _tcschr(movp, TEXT('/')); + if (!pbs) break; + *pbs = TEXT('\0'); + FtpCreateDirectory(hConn, path + 1); + InternetGetLastResponseInfo(&err, buf, &(rslt = sizeof(buf))); + *(movp + lstrlen(movp)) = TEXT('/'); + movp = _tcschr(movp, TEXT('/')) + 1; + } + if(status != ERR_CREATEDIR && + (hFile = FtpOpenFile(hConn, path + 1, GENERIC_WRITE, + FTP_TRANSFER_TYPE_BINARY|INTERNET_FLAG_RELOAD,0)) == NULL) + { + status = ERR_PATH; + if(InternetGetLastResponseInfo(&err, buf, &(rslt = sizeof(buf)))) + lstrcpyn(szStatus[status], _tcsstr(buf, TEXT("550")), sizeof(szStatus[0]) / sizeof(TCHAR)); + } + } + // may be firewall related error, let's give user time to disable it + else if(gle == 12003) // ERROR_INTERNET_EXTENDED_ERROR + { + if(_tcsstr(buf, TEXT("550"))) + { + status = ERR_NOTFOUND; + lstrcpyn(szStatus[status], _tcsstr(buf, TEXT("550")), sizeof(szStatus[0]) / sizeof(TCHAR)); + } + else + { + lstrcpyn(szStatus[status], buf, sizeof(szStatus[0]) / sizeof(TCHAR)); + } + } + // timeout (firewall or dropped connection problem) + else if(gle == 12002) // ERROR_INTERNET_TIMEOUT + { + if(!silent) + resume = true; + status = ERR_URLOPEN; + } + } + else + InternetGetLastResponseInfo(&err, buf, &(rslt = sizeof(buf))); + if (hFile && NOT_AVAILABLE == fs) + { + FARPROC ftpgfs = GetWininetProcAddress("FtpGetFileSize"); // IE5+ + if (ftpgfs) + { + DWORD shi, slo = ((DWORD(WINAPI*)(HINTERNET,DWORD*))ftpgfs)(hFile, &shi); + if (slo != -1 && !shi) fs = slo; + } + } + return hFile; +} + + +/***************************************************** +* FUNCTION NAME: openHttpFile() +* PURPOSE: +* file open, size request, re-get lseek +* SPECIAL CONSIDERATIONS: +* +*****************************************************/ +HINTERNET openHttpFile(HINTERNET hConn, INTERNET_SCHEME nScheme, TCHAR *path) +{ + TCHAR buf[256] = TEXT(""); + HINTERNET hFile; + DWORD rslt, err; + bool first_attempt = true;; + +// test connection for PUT, the only way to do this before sending data +// OPTIONS fails on HttpOpenRequest step for HTTPS +// but works for HEAD I guess + if(fput)// && nScheme != INTERNET_SCHEME_HTTPS) + { +// old proxy's may not support OPTIONS request, so changed to HEAD.... + if((hFile = HttpOpenRequest(hConn, TEXT("HEAD"), path, NULL, NULL, NULL, +// if((hFile = HttpOpenRequest(hConn, TEXT("OPTIONS"), path, NULL, NULL, NULL, + INTERNET_FLAG_RELOAD | INTERNET_FLAG_KEEP_CONNECTION | + (nocookies ? (INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_COOKIES) : 0), 0)) != NULL) + { + if(*szAuth) + { + wsprintf(buf, PROXY_AUTH_HDR, szAuth); + HttpAddRequestHeaders(hFile, buf, -1, + HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE); + } +resend_proxy1: + if(*szBasic) + { + wsprintf(buf, HOST_AUTH_HDR, szBasic); + HttpAddRequestHeaders(hFile, buf, -1, + HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE); + } +resend_auth1: + if(HttpSendRequest(hFile, NULL, 0, NULL, 0)) + { + queryStatus(hFile); +// may be don't need to read all from socket, but this looks safer + while(InternetReadFile(hFile, buf, sizeof(buf), &rslt) && rslt > 0) {} + if(!silent && (status == ERR_PROXY || status == ERR_AUTH))// || status == ERR_FORBIDDEN)) + { + rslt = InternetErrorDlg(hDlg, hFile, + ERROR_INTERNET_INCORRECT_PASSWORD, + FLAGS_ERROR_UI_FILTER_FOR_ERRORS | + FLAGS_ERROR_UI_FLAGS_GENERATE_DATA | + FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS, + NULL); + if (rslt == ERROR_INTERNET_FORCE_RETRY) + { + status = ST_URLOPEN; + if(status == ERR_PROXY) goto resend_proxy1; + else goto resend_auth1; + } + else + { + status = ST_CANCELLED; + } + + } + // no such file is OK for PUT. server first checks authentication + if(status == ERR_NOTFOUND || status == ERR_FORBIDDEN || status == ERR_NOTALLOWED) + { +// MessageBox(childwnd, TEXT("NOT_FOUND"), "", 0); + status = ST_URLOPEN; + } + // parameters might be updated during dialog popup + if(status == ST_URLOPEN) + { + *buf = 0; + if(HttpQueryInfo(hFile, HTTP_QUERY_AUTHORIZATION, buf, &(rslt = sizeof(buf)), NULL) && *buf) + lstrcpyn(szBasic, buf, rslt); + *buf = 0; + if(HttpQueryInfo(hFile, HTTP_QUERY_PROXY_AUTHORIZATION, buf, &(rslt = sizeof(buf)), NULL) && *buf) + lstrcpyn(szAuth, buf, rslt); + } + } + else status = ERR_SENDREQUEST; + InternetCloseHandle(hFile); + } + else status = ERR_OPENREQUEST; + } +// request itself + if(status == ST_URLOPEN) + { + DWORD secflags = nScheme == INTERNET_SCHEME_HTTPS ? MY_HTTPS_FLAGS : 0; + if (Option_IgnoreCertIssues()) secflags |= MY_WEAKSECURITY_CERT_FLAGS; + DWORD cokflags = nocookies ? (INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_COOKIES) : 0; + if((hFile = HttpOpenRequest(hConn, fput ? TEXT("PUT") : (fhead ? TEXT("HEAD") : (szPost ? TEXT("POST") : NULL)), + path, NULL, NULL, NULL, + // INTERNET_FLAG_RELOAD conflicts with reget - hidden re-read from beginning has place + // INTERNET_FLAG_RESYNCHRONIZE // note - sync may not work with some http servers + // reload on first connect (and any req. except GET), just continue on resume. + // HTTP Proxy still is a problem for reget + (cnt ? 0 : INTERNET_FLAG_RELOAD) | INTERNET_FLAG_KEEP_CONNECTION | cokflags | secflags, 0)) != NULL) + { + if(*szAuth) + { + wsprintf(buf, PROXY_AUTH_HDR, szAuth); + HttpAddRequestHeaders(hFile, buf, -1, + HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE); + } +resend_proxy2: + if(szPost != NULL) + HttpAddRequestHeaders(hFile, POST_HEADER, + -1, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE); + if(*post_fname) + HttpAddRequestHeadersA(hFile, post_fname, + -1, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE); + if(szHeader != NULL) + HttpAddRequestHeaders(hFile, szHeader, -1, + HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE); + if(*szBasic) + { + wsprintf(buf, HOST_AUTH_HDR, szBasic); + HttpAddRequestHeaders(hFile, buf, -1, + HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE); + } + if(fput) + { + wsprintf(buf, PUT_HEADER, fs); + HttpAddRequestHeaders(hFile, buf, -1, + HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE); + } +resend_auth2: + first_attempt = true; + if(nScheme == INTERNET_SCHEME_HTTPS) + { + if(!mySendRequest(hFile)) + { + InternetQueryOption (hFile, INTERNET_OPTION_SECURITY_FLAGS, + (LPVOID)&rslt, &(err = sizeof(rslt))); + rslt |= Option_IgnoreCertIssues() ? MY_WEAKSECURITY_CERT_FLAGS : 0; + InternetSetOption (hFile, INTERNET_OPTION_SECURITY_FLAGS, + &rslt, sizeof(rslt) ); + } + else first_attempt = false; + } +// https Request answer may be after optional second Send only on Win98 + if(!first_attempt || mySendRequest(hFile)) + { +// no status for PUT - headers were sent only. And not need to get size / set position + if(!fput) + { + queryStatus(hFile); + if(!silent && (status == ERR_PROXY || status == ERR_AUTH)) + { + rslt = InternetErrorDlg(hDlg, hFile, + ERROR_INTERNET_INCORRECT_PASSWORD, + FLAGS_ERROR_UI_FILTER_FOR_ERRORS | + FLAGS_ERROR_UI_FLAGS_GENERATE_DATA | + FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS, + NULL); + if (rslt == ERROR_INTERNET_FORCE_RETRY) + { + status = ST_URLOPEN; + if(status == ERR_PROXY) goto resend_proxy2; + else goto resend_auth2; + } + else + status = ST_CANCELLED; + + } +// get size / set position + if(status == ST_URLOPEN) + { + if(cnt == 0) + { + if(HttpQueryInfo(hFile, HTTP_QUERY_CONTENT_LENGTH, buf, + &(rslt = sizeof(buf)), NULL)) + fs = myatou(buf); + else + fs = NOT_AVAILABLE; + } + else + { + if((int)InternetSetFilePointer(hFile, cnt, NULL, FILE_BEGIN, 0) == -1) + status = ERR_REGET; + } + } + } + } + else + { + if(!queryStatus(hFile)) + status = ERR_SENDREQUEST; + } + } + else status = ERR_OPENREQUEST; + } + return hFile; +} + +/***************************************************** +* FUNCTION NAME: inetTransfer() +* PURPOSE: +* http/ftp file transfer +* SPECIAL CONSIDERATIONS: +* +*****************************************************/ +DWORD __stdcall inetTransfer(void *hw) +{ + HINTERNET hSes, hConn, hFile; + HANDLE localFile = NULL; + HWND hDlg = (HWND)hw; + DWORD lastCnt, rslt, err; + static TCHAR hdr[2048]; + TCHAR *host = (TCHAR*)LocalAlloc(LPTR, g_stringsize * sizeof(TCHAR)), + *path = (TCHAR*)LocalAlloc(LPTR, g_stringsize * sizeof(TCHAR)), + *params = (TCHAR*)LocalAlloc(LPTR, g_stringsize * sizeof(TCHAR)), + *user = (TCHAR*)LocalAlloc(LPTR, g_stringsize * sizeof(TCHAR)), + *passwd = (TCHAR*)LocalAlloc(LPTR, g_stringsize * sizeof(TCHAR)); + + URL_COMPONENTS uc = {sizeof(URL_COMPONENTS), NULL, 0, + (INTERNET_SCHEME)0, host, g_stringsize, 0 , user, g_stringsize, + passwd, g_stringsize, path, g_stringsize, params, g_stringsize}; + + if((hSes = InternetOpen(szUserAgent, openType, szProxy, NULL, 0)) != NULL) + { + if(InternetQueryOption(hSes, INTERNET_OPTION_CONNECTED_STATE, &(rslt=0), + &(lastCnt=sizeof(DWORD))) && + (rslt & INTERNET_STATE_DISCONNECTED_BY_USER)) + { + INTERNET_CONNECTED_INFO ci = {INTERNET_STATE_CONNECTED, 0}; + InternetSetOption(hSes, + INTERNET_OPTION_CONNECTED_STATE, &ci, sizeof(ci)); + } + if(timeout > 0) + lastCnt = InternetSetOption(hSes, INTERNET_OPTION_CONNECT_TIMEOUT, &timeout, sizeof(timeout)); + if(receivetimeout > 0) + InternetSetOption(hSes, INTERNET_OPTION_RECEIVE_TIMEOUT, &receivetimeout, sizeof(receivetimeout)); + // 60 sec WinInet.dll detach delay on socket time_wait fix + myFtpCommand = (FTP_CMD) GetWininetProcAddress( +#ifdef UNICODE + "FtpCommandW" +#else + "FtpCommandA" +#endif + ); + while(!popstring(url) && lstrcmpi(url, TEXT("/end")) != 0) + { + // too many customers requested not to do this + // sf(hDlg); + if(popstring(fn) != 0 || lstrcmpi(url, TEXT("/end")) == 0) break; + status = ST_CONNECTING; + cnt = fs = *host = *user = *passwd = *path = *params = 0; + PostMessage(hDlg, WM_TIMER, 1, 0); // show url & fn, do it sync + if(szToStack || (localFile = CreateFile(fn, fput ? GENERIC_READ : GENERIC_WRITE, FILE_SHARE_READ, + NULL, fput ? OPEN_EXISTING : CREATE_ALWAYS, 0, NULL)) != INVALID_HANDLE_VALUE) + { + uc.dwHostNameLength = uc.dwUserNameLength = uc.dwPasswordLength = + uc.dwUrlPathLength = uc.dwExtraInfoLength = g_stringsize; + if(fput) + { + fs = GetFileSize(localFile, NULL); + } + if(InternetCrackUrl(url, 0, 0/*ICU_ESCAPE*/ , &uc)) + { + // auth headers for HTTP PUT seems to be lost, preparing encoded login:password + if(*user && *passwd) + { + wsprintf(hdr, TEXT("%s:%s"), user, passwd); + // does unicode version of encoding works correct? + // are user and passwd ascii only? + encode_base64(lstrlen(hdr), hdr, szBasic); + *hdr = 0; + } + lstrcat(path, params); // BUGBUG: Could overflow path? + transfStart = GetTickCount(); + do + { + // re-PUT to already deleted tmp file on http server is not possible. + // the same with POST - must re-send data to server. for 'resume' loop + if((fput && uc.nScheme != INTERNET_SCHEME_FTP) || szPost) + { + cnt = 0; + SetFilePointer(localFile, 0, NULL, FILE_BEGIN); + } + status = ST_CONNECTING; + lastCnt = cnt; + if((hConn = InternetConnect(hSes, host, uc.nPort, + lstrlen(user) > 0 ? user : NULL, + lstrlen(passwd) > 0 ? passwd : NULL, + uc.nScheme == INTERNET_SCHEME_FTP ? INTERNET_SERVICE_FTP : INTERNET_SERVICE_HTTP, + uc.nScheme == INTERNET_SCHEME_FTP ? INTERNET_FLAG_PASSIVE : 0, 0)) != NULL) + { + status = ST_URLOPEN; + hFile = uc.nScheme == INTERNET_SCHEME_FTP ? + openFtpFile(hConn, path) : openHttpFile(hConn, uc.nScheme, path); + if(status != ST_URLOPEN && hFile != NULL) + { + InternetCloseHandle(hFile); + hFile = NULL; + } + if(hFile != NULL) + { + if(fhead) + {// repeating calls clear headers.. + if(HttpQueryInfo(hFile, HTTP_QUERY_RAW_HEADERS_CRLF, hdr, &(rslt=2048), NULL)) + { + if(szToStack) + { + for (DWORD i = 0; cntToStack < g_stringsize && i < rslt; i++, cntToStack++) + *(szToStack + cntToStack) = hdr[i]; // ASCII to TCHAR + } + else + { + WriteFile(localFile, hdr, rslt, &lastCnt, NULL); + } + } + status = ST_OK; + } + else + { + HWND hBar = GetDlgItem(hDlg, IDC_PROGRESS1); + SendDlgItemMessage(hDlg, IDC_PROGRESS1, PBM_SETPOS, 0, 0); + SetWindowText(GetDlgItem(hDlg, IDC_STATIC5), fs == NOT_AVAILABLE ? TEXT("Not Available") : TEXT("")); + SetWindowText(GetDlgItem(hDlg, IDC_STATIC4), fs == NOT_AVAILABLE ? TEXT("Unknown") : TEXT("")); + SetWindowLong(hBar, GWL_STYLE, fs == NOT_AVAILABLE ? + (GetWindowLong(hBar, GWL_STYLE) | PBS_MARQUEE) : (GetWindowLong(hBar, GWL_STYLE) & ~PBS_MARQUEE)); + SendDlgItemMessage(hDlg, IDC_PROGRESS1, PBM_SETMARQUEE, (WPARAM)(fs == NOT_AVAILABLE ? 1 : 0), (LPARAM)50 ); + fileTransfer(localFile, hFile); + if(fput && uc.nScheme != INTERNET_SCHEME_FTP) + { + rslt = HttpEndRequest(hFile, NULL, 0, 0); + queryStatus(hFile); + } + } + InternetCloseHandle(hFile); + } + InternetCloseHandle(hConn); + } + else + { + status = ERR_CONNECT; + if(uc.nScheme == INTERNET_SCHEME_FTP && + InternetGetLastResponseInfo(&err, hdr, &(rslt = sizeof(hdr))) && + _tcsstr(hdr, TEXT("530"))) + { + lstrcpyn(szStatus[status], _tcsstr(hdr, TEXT("530")), sizeof(szStatus[0]) / sizeof(TCHAR)); + } + else + { + rslt = GetLastError(); + if((rslt == 12003 || rslt == 12002) && !silent) + resume = true; + } + } + } while(((!fput || uc.nScheme == INTERNET_SCHEME_FTP) && + cnt > lastCnt && + status == ERR_TRANSFER && + SleepEx(PAUSE1_SEC * 1000, false) == 0 && + (status = ST_PAUSE) != ST_OK && + SleepEx(PAUSE2_SEC * 1000, false) == 0) + || (resume && + status != ST_OK && + status != ST_CANCELLED && + status != ERR_NOTFOUND && + ShowWindow(hDlg, SW_HIDE) != -1 && + MessageBox(GetParent(hDlg), szResume, *szCaption ? szCaption : PLUGIN_NAME, MB_RETRYCANCEL|MB_ICONWARNING) == IDRETRY && + (status = ST_PAUSE) != ST_OK && + ShowWindow(hDlg, silent ? SW_HIDE : SW_SHOW) == false && + SleepEx(PAUSE3_SEC * 1000, false) == 0)); + } + else status = ERR_CRACKURL; + CloseHandle(localFile); + if(!fput && status != ST_OK && !szToStack) + { + rslt = DeleteFile(fn); + break; + } + } + else status = ERR_FILEOPEN; + } + InternetCloseHandle(hSes); + if (lstrcmpi(url, TEXT("/end"))==0) + pushstring(url); + } + else status = ERR_INETOPEN; + LocalFree(host); + LocalFree(path); + LocalFree(user); + LocalFree(passwd); + LocalFree(params); + if(IsWindow(hDlg)) + PostMessage(hDlg, WM_COMMAND, MAKELONG(IDOK, INTERNAL_OK), 0); + return status; +} + +/***************************************************** +* FUNCTION NAME: fsFormat() +* PURPOSE: +* formats DWORD (max 4 GB) file size for dialog, big MB +* SPECIAL CONSIDERATIONS: +* +*****************************************************/ +void fsFormat(DWORD bfs, TCHAR *b) +{ + if(bfs == NOT_AVAILABLE) + lstrcpy(b, TEXT("???")); + else if(bfs == 0) + lstrcpy(b, TEXT("0")); + else if(bfs < 10 * 1024) + wsprintf(b, TEXT("%u bytes"), bfs); + else if(bfs < 10 * 1024 * 1024) + wsprintf(b, TEXT("%u kB"), bfs / 1024); + else wsprintf(b, TEXT("%u MB"), (bfs / 1024 / 1024)); +} + + +/***************************************************** +* FUNCTION NAME: progress_callback +* PURPOSE: +* old-style progress bar text updates +* SPECIAL CONSIDERATIONS: +* +*****************************************************/ + +void progress_callback(void) +{ + static TCHAR buf[1024] = TEXT(""), b[1024] = TEXT(""); + int time_sofar = max(1, (GetTickCount() - transfStart) / 1000); + int bps = cnt / time_sofar; + int remain = (cnt > 0 && fs != NOT_AVAILABLE) ? (MulDiv(time_sofar, fs, cnt) - time_sofar) : 0; + TCHAR *rtext=szSecond; + if(remain < 0) remain = 0; + if (remain >= 60) + { + remain/=60; + rtext=szMinute; + if (remain >= 60) + { + remain/=60; + rtext=szHour; + } + } + wsprintf(buf, + szProgress, + cnt/1024, + fs > 0 && fs != NOT_AVAILABLE ? MulDiv(100, cnt, fs) : 0, + fs != NOT_AVAILABLE ? fs/1024 : 0, + bps/1024,((bps*10)/1024)%10 + ); + if (remain) wsprintf(buf + lstrlen(buf), + szRemaining, + remain, + rtext, + remain==1?TEXT(""):szPlural + ); + SetDlgItemText(hDlg, IDC_STATIC1, (cnt == 0 || status == ST_CONNECTING) ? szConnecting : buf); + if(fs > 0 && fs != NOT_AVAILABLE) + SendMessage(GetDlgItem(hDlg, IDC_PROGRESS1), PBM_SETPOS, MulDiv(cnt, PB_RANGE, fs), 0); + if (*szCaption == 0) + wsprintf(buf, szDownloading, _tcsrchr(fn, TEXT('\\')) ? _tcsrchr(fn, TEXT('\\')) + 1 : fn); + else + wsprintf(buf, TEXT("%s"),szCaption); + HWND hwndS = GetDlgItem(childwnd, 1006); + if(!silent && hwndS != NULL && IsWindow(hwndS)) + { + GetWindowText(hwndS, b, sizeof(b)); + if(lstrcmp(b, buf) != 0) + SetWindowText(hwndS, buf); + } +} + +/***************************************************** +* FUNCTION NAME: onTimer() +* PURPOSE: +* updates text fields every second +* SPECIAL CONSIDERATIONS: +* +*****************************************************/ +void onTimer(HWND hDlg) +{ + TCHAR b[128]; + DWORD ct = (GetTickCount() - transfStart) / 1000, + tt = (GetTickCount() - startTime) / 1000; + // dialog window caption + wsprintf(b, TEXT("%s - %s"), *szCaption ? szCaption : PLUGIN_NAME, szStatus[status]); + if(fs > 0 && fs != NOT_AVAILABLE && status == ST_DOWNLOAD) + { + wsprintf(b + lstrlen(b), TEXT(" %d%%"), MulDiv(100, cnt, fs)); + } + if(szBanner == NULL) SetWindowText(hDlg, b); + // current file and url + SetDlgItemText(hDlg, IDC_STATIC1, (szAlias && *szAlias) ? szAlias : url); + SetDlgItemText(hDlg, IDC_STATIC2, /*_tcsrchr(fn, '\\') ? _tcsrchr(fn, '\\') + 1 : */fn); + // bytes done and rate + if(cnt > 0) + { + fsFormat(cnt, b); + if(ct > 1 && status == ST_DOWNLOAD) + { + lstrcat(b, TEXT(" ( ")); + fsFormat(cnt / ct, b + lstrlen(b)); + lstrcat(b, TEXT("/sec )")); + } + } + else *b = 0; + SetDlgItemText(hDlg, IDC_STATIC3, b); + // total download time + wsprintf(b, TEXT("%d:%02d:%02d"), tt / 3600, (tt / 60) % 60, tt % 60); + SetDlgItemText(hDlg, IDC_STATIC6, b); + // file size, time remaining, progress bar + if(fs > 0 && fs != NOT_AVAILABLE) + { + fsFormat(fs, b); + SetDlgItemText(hDlg, IDC_STATIC5, b); + SendDlgItemMessage(hDlg, IDC_PROGRESS1, PBM_SETPOS, MulDiv(cnt, PB_RANGE, fs), 0); + if(cnt > 5000) + { + ct = MulDiv(fs - cnt, ct, cnt); + wsprintf(b, TEXT("%d:%02d:%02d"), ct / 3600, (ct / 60) % 60, ct % 60); + } + else *b = 0; + SetWindowText(GetDlgItem(hDlg, IDC_STATIC4), b); + } +} + +/***************************************************** +* FUNCTION NAME: centerDlg() +* PURPOSE: +* centers dlg on NSIS parent +* SPECIAL CONSIDERATIONS: +* +*****************************************************/ +void centerDlg(HWND hDlg) +{ + HWND hwndParent = GetParent(hDlg); + RECT nsisRect, dlgRect, waRect; + int dlgX, dlgY, dlgWidth, dlgHeight; + + if(hwndParent == NULL || silent) + return; + if(popup) + GetWindowRect(hwndParent, &nsisRect); + else GetClientRect(hwndParent, &nsisRect); + GetWindowRect(hDlg, &dlgRect); + + dlgWidth = dlgRect.right - dlgRect.left; + dlgHeight = dlgRect.bottom - dlgRect.top; + dlgX = (nsisRect.left + nsisRect.right - dlgWidth) / 2; + dlgY = (nsisRect.top + nsisRect.bottom - dlgHeight) / 2; + + if(popup) + { + SystemParametersInfo(SPI_GETWORKAREA, 0, &waRect, 0); + if(dlgX > waRect.right - dlgWidth) + dlgX = waRect.right - dlgWidth; + if(dlgX < waRect.left) dlgX = waRect.left; + if(dlgY > waRect.bottom - dlgHeight) + dlgY = waRect.bottom - dlgHeight; + if(dlgY < waRect.top) dlgY = waRect.top; + } + else dlgY += 20; + + SetWindowPos(hDlg, HWND_TOP, dlgX, dlgY, 0, 0, SWP_NOSIZE); +} + +/***************************************************** +* FUNCTION NAME: onInitDlg() +* PURPOSE: +* dlg init +* SPECIAL CONSIDERATIONS: +* +*****************************************************/ +void onInitDlg(HWND hDlg) +{ + HFONT hFont; + HWND hPrbNew; + HWND hPrbOld; + HWND hCan = GetDlgItem(hDlg, IDCANCEL); + + if(childwnd) + { + hPrbNew = GetDlgItem(hDlg, IDC_PROGRESS1); + hPrbOld = GetDlgItem(childwnd, 0x3ec); + + // Backland' fix for progress bar redraw/style issue. + // Original bar may be hidden because of interfernce with other plug-ins. + LONG prbStyle = WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; + if(hPrbOld != NULL) + { + prbStyle |= GetWindowLong(hPrbOld, GWL_STYLE); + } + SetWindowLong(hPrbNew, GWL_STYLE, prbStyle); + + if(!popup) + { + if((hFont = (HFONT)SendMessage(childwnd, WM_GETFONT, 0, 0)) != NULL) + { + SendDlgItemMessage(hDlg, IDC_STATIC1, WM_SETFONT, (WPARAM)hFont, 0); + SendDlgItemMessage(hDlg, IDCANCEL, WM_SETFONT, (WPARAM)hFont, 0); + } + if(*szCancel == 0) + GetWindowText(GetDlgItem(GetParent(childwnd), IDCANCEL), szCancel, sizeof(szCancel)); + SetWindowText(hCan, szCancel); + SetWindowPos(hPrbNew, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); + } + } + + if(nocancel) + { + if(hCan != NULL) + ShowWindow(hCan, SW_HIDE); + if(popup) + SetWindowLong(hDlg, GWL_STYLE, GetWindowLong(hDlg, GWL_STYLE) ^ WS_SYSMENU); + } + SendDlgItemMessage(hDlg, IDC_PROGRESS1, PBM_SETRANGE, + 0, MAKELPARAM(0, PB_RANGE)); + if(szBanner != NULL) + { + SendDlgItemMessage(hDlg, IDC_STATIC13, STM_SETICON, + (WPARAM)LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(103)), 0); + SetDlgItemText(hDlg, IDC_STATIC12, szBanner); + SetWindowText(hDlg, *szCaption ? szCaption : PLUGIN_NAME); + } + SetTimer(hDlg, 1, 1000, NULL); + if(*szUrl != 0) + { + SetDlgItemText(hDlg, IDC_STATIC20, szUrl); + SetDlgItemText(hDlg, IDC_STATIC21, szDownloading); + SetDlgItemText(hDlg, IDC_STATIC22, szConnecting); + SetDlgItemText(hDlg, IDC_STATIC23, szProgress); + SetDlgItemText(hDlg, IDC_STATIC24, szSecond); + SetDlgItemText(hDlg, IDC_STATIC25, szRemaining); + } +} + +/***************************************************** +* FUNCTION NAME: dlgProc() +* PURPOSE: +* dlg message handling procedure +* SPECIAL CONSIDERATIONS: +* todo: better dialog design +*****************************************************/ +INT_PTR CALLBACK dlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) +{ + switch(message) + { + case WM_INITDIALOG: + onInitDlg(hDlg); + centerDlg(hDlg); + return false; + case WM_PAINT: + // child dialog redraw problem. return false is important + { + HWND hS1 = GetDlgItem(hDlg, IDC_STATIC1), hC = GetDlgItem(hDlg, IDCANCEL), hP1 = GetDlgItem(hDlg, IDC_PROGRESS1); + RedrawWindow(hS1, NULL, NULL, RDW_INVALIDATE); + RedrawWindow(hC, NULL, NULL, RDW_INVALIDATE); + RedrawWindow(hP1, NULL, NULL, RDW_INVALIDATE); + UpdateWindow(hS1); + UpdateWindow(hC); + UpdateWindow(hP1); + } + return false; + case WM_TIMER: + if(!silent && IsWindow(hDlg)) + { + // long connection period and paused state updates + if(status != ST_DOWNLOAD && GetTickCount() - transfStart > PROGRESS_MS) + transfStart += PROGRESS_MS; + if(popup) onTimer(hDlg); else progress_callback(); + RedrawWindow(GetDlgItem(hDlg, IDC_STATIC1), NULL, NULL, RDW_INVALIDATE); + RedrawWindow(GetDlgItem(hDlg, IDCANCEL), NULL, NULL, RDW_INVALIDATE); + RedrawWindow(GetDlgItem(hDlg, IDC_PROGRESS1), NULL, NULL, RDW_INVALIDATE); + } + break; + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case IDCANCEL: + if(nocancel) break; + if(szQuestion && + MessageBox(hDlg, szQuestion, *szCaption ? szCaption : PLUGIN_NAME, MB_ICONWARNING|MB_YESNO) == IDNO) + break; + status = ST_CANCELLED; + // FallThrough + case IDOK: + if(status != ST_CANCELLED && HIWORD(wParam) != INTERNAL_OK) break; + // otherwise in the silent mode next banner windows may go to background + // if(silent) sf(hDlg); + KillTimer(hDlg, 1); + DestroyWindow(hDlg); + break; + } + return false; + default: + return false; + } + return true; +} + +/***************************************************** +* FUNCTION NAME: get() +* PURPOSE: +* http/https/ftp file download entry point +* SPECIAL CONSIDERATIONS: +* +*****************************************************/ +extern "C" +void __declspec(dllexport) __cdecl get(HWND hwndParent, + int string_size, + TCHAR *variables, + stack_t **stacktop, + extra_parameters *extra + ) +{ + HANDLE hThread; + DWORD dwThreadId; + MSG msg; + TCHAR szUsername[64]=TEXT(""), // proxy params + szPassword[64]=TEXT(""); + + + EXDLL_INIT(); + +// for repeating /nounload plug-un calls - global vars clean up + silent = popup = resume = nocancel = noproxy = nocookies = false; + g_ignorecertissues = false; + myFtpCommand = NULL; + openType = INTERNET_OPEN_TYPE_PRECONFIG; + status = ST_CONNECTING; + *szCaption = *szCancel = *szUserAgent = *szBasic = *szAuth = 0; + + url = (TCHAR*)LocalAlloc(LPTR, string_size * sizeof(TCHAR)); + if(szPost) + { + popstring(url); +#ifdef UNICODE + WideCharToMultiByte(CP_ACP, 0, url, -1, szPost, string_size, NULL, NULL); +#else + lstrcpy(szPost, url); +#endif + fSize = (DWORD)lstrlenA(szPost); + } + // global silent option + if(extra->exec_flags->silent != 0) + silent = true; + // we must take this from stack, or push url back + while(!popstring(url) && *url == TEXT('/')) + { + if(lstrcmpi(url, TEXT("/silent")) == 0) + silent = true; + else if(lstrcmpi(url, TEXT("/weaksecurity")) == 0) + g_ignorecertissues = true; + else if(lstrcmpi(url, TEXT("/caption")) == 0) + popstring(szCaption); + else if(lstrcmpi(url, TEXT("/username")) == 0) + popstring(szUsername); + else if(lstrcmpi(url, TEXT("/password")) == 0) + popstring(szPassword); + else if(lstrcmpi(url, TEXT("/nocancel")) == 0) + nocancel = true; + else if(lstrcmpi(url, TEXT("/nocookies")) == 0) + nocookies = true; + else if(lstrcmpi(url, TEXT("/noproxy")) == 0) + openType = INTERNET_OPEN_TYPE_DIRECT; + else if(lstrcmpi(url, TEXT("/popup")) == 0) + { + popup = true; + szAlias = (TCHAR*)LocalAlloc(LPTR, string_size * sizeof(TCHAR)); + popstring(szAlias); + } + else if(lstrcmpi(url, TEXT("/resume")) == 0) + { + popstring(url); + if(url[0]) lstrcpy(szResume, url); + resume = true; + } + else if(lstrcmpi(url, TEXT("/translate")) == 0) + { + if(popup) + { + popstring(szUrl); + popstring(szStatus[ST_DOWNLOAD]); // Downloading + popstring(szStatus[ST_CONNECTING]); // Connecting + lstrcpy(szStatus[ST_URLOPEN], szStatus[ST_CONNECTING]); + popstring(szDownloading);// file name + popstring(szConnecting);// received + popstring(szProgress);// file size + popstring(szSecond);// remaining time + popstring(szRemaining);// total time + } + else + { + popstring(szDownloading); + popstring(szConnecting); + popstring(szSecond); + popstring(szMinute); + popstring(szHour); + popstring(szPlural); + popstring(szProgress); + popstring(szRemaining); + } + } + else if(lstrcmpi(url, TEXT("/banner")) == 0) + { + popup = true; + szBanner = (TCHAR*)LocalAlloc(LPTR, string_size * sizeof(TCHAR)); + popstring(szBanner); + } + else if(lstrcmpi(url, TEXT("/canceltext")) == 0) + { + popstring(szCancel); + } + else if(lstrcmpi(url, TEXT("/question")) == 0) + { + szQuestion = (TCHAR*)LocalAlloc(LPTR, string_size * sizeof(TCHAR)); + popstring(szQuestion); + if(*szQuestion == 0) lstrcpy(szQuestion, DEF_QUESTION); + } + else if(lstrcmpi(url, TEXT("/useragent")) == 0) + { + popstring(szUserAgent); + } + else if(lstrcmpi(url, TEXT("/proxy")) == 0) + { + szProxy = (TCHAR*)LocalAlloc(LPTR, string_size * sizeof(TCHAR)); + popstring(szProxy); + openType = INTERNET_OPEN_TYPE_PROXY; + } + else if(lstrcmpi(url, TEXT("/connecttimeout")) == 0) + { + popstring(url); + timeout = myatou(url) * 1000; + } + else if(lstrcmpi(url, TEXT("/receivetimeout")) == 0) + { + popstring(url); + receivetimeout = myatou(url) * 1000; + } + else if(lstrcmpi(url, TEXT("/header")) == 0) + { + szHeader = (TCHAR*)LocalAlloc(LPTR, string_size * sizeof(TCHAR)); + popstring(szHeader); + } + else if(!fput && ((convToStack = lstrcmpi(url, TEXT("/tostackconv")) == 0) || lstrcmpi(url, TEXT("/tostack")) == 0)) + { + szToStack = (TCHAR*)LocalAlloc(LPTR, string_size * sizeof(TCHAR)); + cntToStack = 0; + lstrcpy(fn, TEXT("file")); + } + else if(lstrcmpi(url, TEXT("/file")) == 0) + { + HANDLE hFile = CreateFileA(szPost, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + DWORD rslt; + if(hFile == INVALID_HANDLE_VALUE) + { + status = ERR_FILEOPEN; + goto cleanup; + } + if((fSize = GetFileSize(hFile, NULL)) == 0) + { + CloseHandle(hFile); + status = ERR_FILEREAD; + goto cleanup; + } + wsprintfA(post_fname, "Filename: %s", + strchr(szPost, '\\') ? strrchr(szPost, '\\') + 1 : szPost); + LocalFree(szPost); + szPost = (char*)LocalAlloc(LPTR, fSize); + if(ReadFile(hFile, szPost, fSize, &rslt, NULL) == 0 || rslt != fSize) + { + CloseHandle(hFile); + status = ERR_FILEREAD; + goto cleanup; + } + CloseHandle(hFile); + } + } + pushstring(url); +// if(*szCaption == 0) lstrcpy(szCaption, PLUGIN_NAME); + if(*szUserAgent == 0) lstrcpy(szUserAgent, INETC_USERAGENT); + if(*szPassword && *szUsername) + { + wsprintf(url, TEXT("%s:%s"), szUsername, szPassword); + encode_base64(lstrlen(url), url, szAuth); + } + // may be silent for plug-in, but not so for installer itself - let's try to define 'progress text' + if(hwndParent != NULL && + (childwnd = FindWindowEx(hwndParent, NULL, TEXT("#32770"), NULL)) != NULL && + !silent) + SetDlgItemText(childwnd, 1006, *szCaption ? szCaption : PLUGIN_NAME); + else InitCommonControls(); // or NSIS do this before .onInit? + // cannot embed child dialog to non-existing parent. Using 'silent' to hide it + if(childwnd == NULL && !popup) silent = true; + // let's use hidden popup dlg in the silent mode - works both on .onInit and Page + if(silent) { resume = false; popup = true; } + // google says WS_CLIPSIBLINGS helps to redraw... not in my tests... + if(!popup) + { + unsigned int wstyle = GetWindowLong(childwnd, GWL_STYLE); + wstyle |= WS_CLIPSIBLINGS; + SetWindowLong(childwnd, GWL_STYLE, wstyle); + } + startTime = GetTickCount(); + if((hDlg = CreateDialog(g_hInstance, + MAKEINTRESOURCE(szBanner ? IDD_DIALOG2 : (popup ? IDD_DIALOG1 : IDD_DIALOG3)), + (popup ? hwndParent : childwnd), dlgProc)) != NULL) + { + + if((hThread = CreateThread(NULL, 0, inetTransfer, (LPVOID)hDlg, 0, + &dwThreadId)) != NULL) + { + HWND hButton = GetDlgItem(childwnd, 0x403); + HWND hList = GetDlgItem(childwnd, 0x3f8); + DWORD dwStyleButton = 0; + BOOL fVisibleList = false; + if(!silent) + { + ShowWindow(hDlg, SW_NORMAL); + if(childwnd && !popup) + { + if(hButton) + { + dwStyleButton = GetWindowLong(hButton, GWL_STYLE); + EnableWindow(hButton, false); + } + if(hList) + { + fVisibleList = IsWindowVisible(hList); + ShowWindow(hList, SW_HIDE); + } + } + } + + while(IsWindow(hDlg) && + GetMessage(&msg, NULL, 0, 0) > 0) + { + if(!IsDialogMessage(hDlg, &msg) && + !IsDialogMessage(hwndParent, &msg) && + !TranslateMessage(&msg)) + DispatchMessage(&msg); + } + + if(WaitForSingleObject(hThread, 3000) == WAIT_TIMEOUT) + { + TerminateThread(hThread, 1); + status = ERR_TERMINATED; + } + CloseHandle(hThread); + if(!silent && childwnd) + { + SetDlgItemText(childwnd, 1006, TEXT("")); + if(!popup) + { + if(hButton) + SetWindowLong(hButton, GWL_STYLE, dwStyleButton); + if(hList && fVisibleList) + ShowWindow(hList, SW_SHOW); + } + // RedrawWindow(childwnd, NULL, NULL, RDW_INVALIDATE|RDW_ERASE); + } + } + else + { + status = ERR_THREAD; + DestroyWindow(hDlg); + } + } + else { + status = ERR_DIALOG; + wsprintf(szStatus[status] + lstrlen(szStatus[status]), TEXT(" (Err=%d)"), GetLastError()); + } +cleanup: + // we need to clean up stack from remaining url/file pairs. + // this multiple files download head pain and may be not safe + while(!popstring(url) && lstrcmpi(url, TEXT("/end")) != 0) + { + /* nothing MessageBox(NULL, url, TEXT(""), 0);*/ + } + LocalFree(url); + if(szAlias) LocalFree(szAlias); + if(szBanner) LocalFree(szAlias); + if(szQuestion) LocalFree(szQuestion); + if(szProxy) LocalFree(szProxy); + if(szPost) LocalFree(szPost); + if(szHeader) LocalFree(szHeader); + + url = szProxy = szHeader = szAlias = szQuestion = NULL; + szPost = NULL; + fput = fhead = false; + + if(szToStack && status == ST_OK) + { + if(cntToStack > 0 && convToStack) + { +#ifdef UNICODE + int cp = CP_ACP; + if (0xef == ((BYTE*)szToStack)[0] && 0xbb == ((BYTE*)szToStack)[1] && 0xbf == ((BYTE*)szToStack)[2]) cp = 65001; // CP_UTF8 + if (0xff == ((BYTE*)szToStack)[0] && 0xfe == ((BYTE*)szToStack)[1]) + { + cp = 1200; // UTF-16LE + pushstring((LPWSTR)szToStack); + } + int required = (cp == 1200) ? 0 : MultiByteToWideChar(cp, 0, (CHAR*)szToStack, string_size * sizeof(TCHAR), NULL, 0); + if(required > 0) + { + WCHAR* pszToStackNew = (WCHAR*)LocalAlloc(LPTR, sizeof(WCHAR) * (required + 1)); + if(pszToStackNew) + { + if(MultiByteToWideChar(cp, 0, (CHAR*)szToStack, string_size * sizeof(TCHAR), pszToStackNew, required) > 0) + pushstring(pszToStackNew); + LocalFree(pszToStackNew); + } + } +#else + int required = WideCharToMultiByte(CP_ACP, 0, (WCHAR*)szToStack, -1, NULL, 0, NULL, NULL); + if(required > 0) + { + CHAR* pszToStackNew = (CHAR*)LocalAlloc(LPTR, required + 1); + if(pszToStackNew) + { + if(WideCharToMultiByte(CP_ACP, 0, (WCHAR*)szToStack, -1, pszToStackNew, required, NULL, NULL) > 0) + pushstring(pszToStackNew); + LocalFree(pszToStackNew); + } + } +#endif + } + else + { + pushstring(szToStack); + } + LocalFree(szToStack); + szToStack = NULL; + } + + pushstring(szStatus[status]); +} + +/***************************************************** +* FUNCTION NAME: put() +* PURPOSE: +* http/ftp file upload entry point +* SPECIAL CONSIDERATIONS: +* re-put not works with http, but ftp REST - may be. +*****************************************************/ +extern "C" +void __declspec(dllexport) __cdecl put(HWND hwndParent, + int string_size, + TCHAR *variables, + stack_t **stacktop, + extra_parameters *extra + ) +{ + fput = true; + lstrcpy(szDownloading, TEXT("Uploading %s")); + lstrcpy(szStatus[2], TEXT("Uploading")); + get(hwndParent, string_size, variables, stacktop, extra); +} + +/***************************************************** +* FUNCTION NAME: post() +* PURPOSE: +* http post entry point +* SPECIAL CONSIDERATIONS: +* +*****************************************************/ +extern "C" +void __declspec(dllexport) __cdecl post(HWND hwndParent, + int string_size, + TCHAR *variables, + stack_t **stacktop, + extra_parameters *extra + ) +{ + szPost = (CHAR*)LocalAlloc(LPTR, string_size); + get(hwndParent, string_size, variables, stacktop, extra); +} + +/***************************************************** +* FUNCTION NAME: head() +* PURPOSE: +* http/ftp file upload entry point +* SPECIAL CONSIDERATIONS: +* re-put not works with http, but ftp REST - may be. +*****************************************************/ +extern "C" +void __declspec(dllexport) __cdecl head(HWND hwndParent, + int string_size, + TCHAR *variables, + stack_t **stacktop, + extra_parameters *extra + ) +{ + fhead = true; + get(hwndParent, string_size, variables, stacktop, extra); +} + +/***************************************************** +* FUNCTION NAME: DllMain() +* PURPOSE: +* Dll main (initialization) entry point +* SPECIAL CONSIDERATIONS: +* +*****************************************************/ +#ifdef _VC_NODEFAULTLIB +#define DllMain _DllMainCRTStartup +#endif +EXTERN_C BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + g_hInstance = hinstDLL; + return TRUE; +} diff --git a/agent/installer/inetc/Contrib/Inetc/inetc.rc b/agent/installer/inetc/Contrib/Inetc/inetc.rc new file mode 100644 index 00000000000..afd10fb8ebe --- /dev/null +++ b/agent/installer/inetc/Contrib/Inetc/inetc.rc @@ -0,0 +1,199 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Russian (Russia) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS) +LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT +#pragma code_page(1251) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // Russian (Russia) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DIALOG1 DIALOGEX 0, 0, 286, 71 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Inetc plug-in" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + LTEXT "",IDC_STATIC1,50,4,230,12,SS_CENTERIMAGE,WS_EX_STATICEDGE + LTEXT "",IDC_STATIC2,50,18,230,12,SS_CENTERIMAGE,WS_EX_STATICEDGE + CTEXT "",IDC_STATIC3,50,32,102,12,SS_CENTERIMAGE,WS_EX_STATICEDGE + CTEXT "",IDC_STATIC4,220,32,60,12,SS_CENTERIMAGE,WS_EX_STATICEDGE + CONTROL "Progress1",IDC_PROGRESS1,"msctls_progress32",NOT WS_VISIBLE,5,62,275,7 + CTEXT "",IDC_STATIC5,50,46,102,12,SS_CENTERIMAGE,WS_EX_STATICEDGE + CTEXT "",IDC_STATIC6,220,46,60,12,SS_CENTERIMAGE,WS_EX_STATICEDGE + CONTROL "URL",IDC_STATIC20,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,5,6,44,10 + CONTROL "File name",IDC_STATIC21,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,5,20,44,10 + CONTROL "Transfered",IDC_STATIC22,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,5,34,44,10 + CONTROL "File size",IDC_STATIC23,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,5,48,44,10 + CONTROL "Remaining time",IDC_STATIC24,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,164,34,55,10 + CONTROL "Total time",IDC_STATIC25,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,164,48,55,10 +END + +IDD_DIALOG2 DIALOG 0, 0, 226, 62 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Inetc plug-in" +FONT 8, "MS Sans Serif" +BEGIN + ICON 103,IDC_STATIC13,4,4,20,20 + LTEXT "Please wait",IDC_STATIC12,35,6,184,28 + CONTROL "Progress1",IDC_PROGRESS1,"msctls_progress32",NOT WS_VISIBLE,12,40,201,11 +END + +IDD_DIALOG3 DIALOG 0, 0, 266, 62 +STYLE DS_SETFONT | DS_CONTROL | WS_CHILD | WS_VISIBLE +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "Progress1",IDC_PROGRESS1,"msctls_progress32",0x0,0,23,266,11 + CTEXT "",IDC_STATIC1,0,8,266,11 + PUSHBUTTON "Cancel",IDCANCEL,166,41,80,16 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_DIALOG1, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 279 + TOPMARGIN, 7 + BOTTOMMARGIN, 64 + END + + IDD_DIALOG2, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 219 + TOPMARGIN, 7 + BOTTOMMARGIN, 55 + END + + IDD_DIALOG3, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 259 + TOPMARGIN, 7 + BOTTOMMARGIN, 55 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (United Kingdom) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,5,2 + PRODUCTVERSION 1,0,5,2 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "FileDescription", "inetc NSIS plug-in" + VALUE "FileVersion", "1.0.5.2" + VALUE "InternalName", "inetc.dll" + VALUE "LegalCopyright", "Copyright © Takhir Bedertdinov" + VALUE "OriginalFilename", "inetc.dll" + VALUE "ProductName", "inetc NSIS plug-in" + VALUE "ProductVersion", "1.0.5.2" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // English (United Kingdom) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/agent/installer/inetc/Contrib/Inetc/inetc.sln b/agent/installer/inetc/Contrib/Inetc/inetc.sln new file mode 100644 index 00000000000..2b2006d4f78 --- /dev/null +++ b/agent/installer/inetc/Contrib/Inetc/inetc.sln @@ -0,0 +1,42 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "inetc", "inetc.vcxproj", "{6B2D8C40-38A9-457A-9FA6-BED0108CAC37}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug Unicode|Win32 = Debug Unicode|Win32 + Debug Unicode|x64 = Debug Unicode|x64 + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release Unicode|Win32 = Release Unicode|Win32 + Release Unicode|x64 = Release Unicode|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Debug Unicode|Win32.ActiveCfg = Debug Unicode|Win32 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Debug Unicode|Win32.Build.0 = Debug Unicode|Win32 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Debug Unicode|Win32.Deploy.0 = Debug Unicode|Win32 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Debug Unicode|x64.ActiveCfg = Debug Unicode|x64 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Debug Unicode|x64.Build.0 = Debug Unicode|x64 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Debug|Win32.ActiveCfg = Debug|Win32 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Debug|Win32.Build.0 = Debug|Win32 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Debug|Win32.Deploy.0 = Debug|Win32 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Debug|x64.ActiveCfg = Debug|x64 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Debug|x64.Build.0 = Debug|x64 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Release Unicode|Win32.ActiveCfg = Release Unicode|Win32 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Release Unicode|Win32.Build.0 = Release Unicode|Win32 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Release Unicode|Win32.Deploy.0 = Release Unicode|Win32 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Release Unicode|x64.ActiveCfg = Release Unicode|x64 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Release Unicode|x64.Build.0 = Release Unicode|x64 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Release|Win32.ActiveCfg = Release|Win32 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Release|Win32.Build.0 = Release|Win32 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Release|Win32.Deploy.0 = Release|Win32 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Release|x64.ActiveCfg = Release|x64 + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/agent/installer/inetc/Contrib/Inetc/inetc.vcxproj b/agent/installer/inetc/Contrib/Inetc/inetc.vcxproj new file mode 100644 index 00000000000..a5e149adb7b --- /dev/null +++ b/agent/installer/inetc/Contrib/Inetc/inetc.vcxproj @@ -0,0 +1,441 @@ + + + + + Debug Unicode + Win32 + + + Debug Unicode + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Unicode + Win32 + + + Release Unicode + x64 + + + Release + Win32 + + + Release + x64 + + + + + + {6B2D8C40-38A9-457A-9FA6-BED0108CAC37} + + + + DynamicLibrary + v110 + Unicode + + + DynamicLibrary + v110 + Unicode + + + DynamicLibrary + v110 + MultiByte + + + DynamicLibrary + v110 + MultiByte + + + DynamicLibrary + v110 + Unicode + + + DynamicLibrary + v110 + Unicode + + + DynamicLibrary + v110 + MultiByte + + + DynamicLibrary + v110 + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + $(SolutionDir)..\..\Plugins\ + + + false + $(ProjectName)64 + $(SolutionDir)..\..\Plugins\ + + + $(SolutionDir)..\..\Unicode\Plugins\ + true + false + + + true + false + $(ProjectName)64 + + + $(SolutionDir)..\..\Plugins\ + false + + + false + $(ProjectName)64 + + + false + $(SolutionDir)..\..\Unicode\Plugins\ + + + false + $(ProjectName)64 + $(SolutionDir)..\..\Unicode\Plugins\ + + + + MultiThreaded + MinSpace + true + Level3 + WIN32;NDEBUG;_WINDOWS;_USRDLL;inetc_EXPORTS;_VC80_UPGRADE=0x0600;%(PreprocessorDefinitions) + false + + + true + NDEBUG;%(PreprocessorDefinitions) + .\debug\inetc.tlb + true + Win32 + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\debug\inetc.bsc + + + true + true + wininet.lib;comctl32.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + false + DllMain + libc.lib + true + + + + + MultiThreaded + MinSpace + true + Level3 + WIN32;NDEBUG;_WINDOWS;_USRDLL;inetc_EXPORTS;_VC80_UPGRADE=0x0600;%(PreprocessorDefinitions) + false + + + true + NDEBUG;%(PreprocessorDefinitions) + .\debug\inetc.tlb + true + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\debug\inetc.bsc + + + true + true + true + wininet.lib;comctl32.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + false + libc.lib + DllMain + + + + + MultiThreadedDebug + Disabled + true + Level3 + EditAndContinue + EnableFastChecks + WIN32;_DEBUG;_WINDOWS;_USRDLL;inetc_EXPORTS;_VC80_UPGRADE=0x0600;%(PreprocessorDefinitions) + false + + + true + _DEBUG;%(PreprocessorDefinitions) + .\Debug_Unicode\inetc.tlb + true + Win32 + + + 0x0409 + _DEBUG;%(PreprocessorDefinitions) + + + true + .\Debug_Unicode\inetc.bsc + + + true + true + .\Debug_Unicode\inetc.lib + wininet.lib;comctl32.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + false + + + + + MultiThreadedDebug + Disabled + true + Level3 + ProgramDatabase + EnableFastChecks + WIN32;_DEBUG;_WINDOWS;_USRDLL;inetc_EXPORTS;_VC80_UPGRADE=0x0600;%(PreprocessorDefinitions) + false + + + true + _DEBUG;%(PreprocessorDefinitions) + .\Debug_Unicode\inetc.tlb + true + + + 0x0409 + _DEBUG;%(PreprocessorDefinitions) + + + true + .\Debug_Unicode\inetc.bsc + + + true + true + .\Debug_Unicode\inetc.lib + wininet.lib;comctl32.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + false + + + + + MultiThreadedDebug + Disabled + true + Level3 + EditAndContinue + WIN32;_DEBUG;_WINDOWS;_USRDLL;inetc_EXPORTS;_VC80_UPGRADE=0x0600;%(PreprocessorDefinitions) + EnableFastChecks + + + true + _DEBUG;%(PreprocessorDefinitions) + .\Debug\inetc.tlb + true + Win32 + + + 0x0409 + _DEBUG;%(PreprocessorDefinitions) + + + true + .\Debug\inetc.bsc + + + true + true + true + wininet.lib;comctl32.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + false + + + + + MultiThreadedDebug + Disabled + true + Level3 + ProgramDatabase + WIN32;_DEBUG;_WINDOWS;_USRDLL;inetc_EXPORTS;_VC80_UPGRADE=0x0600;%(PreprocessorDefinitions) + EnableFastChecks + + + true + _DEBUG;%(PreprocessorDefinitions) + .\Debug\inetc.tlb + true + + + 0x0409 + _DEBUG;%(PreprocessorDefinitions) + + + true + .\Debug\inetc.bsc + + + true + true + true + wininet.lib;comctl32.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + false + + + + + MultiThreaded + MinSpace + true + Level3 + WIN32;NDEBUG;_WINDOWS;UNICODE;_USRDLL;inetc_EXPORTS;_VC80_UPGRADE=0x0600;%(PreprocessorDefinitions) + false + + + true + NDEBUG;%(PreprocessorDefinitions) + .\Debug_Unicode\inetc.tlb + true + Win32 + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\Debug_Unicode\inetc.bsc + + + true + true + wininet.lib;comctl32.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + true + false + DllMain + libc.lib + + + + + MultiThreaded + MinSpace + true + Level3 + WIN32;NDEBUG;_WINDOWS;UNICODE;_USRDLL;inetc_EXPORTS;_VC80_UPGRADE=0x0600;%(PreprocessorDefinitions) + false + + + true + NDEBUG;%(PreprocessorDefinitions) + .\Debug_Unicode\inetc.tlb + true + + + 0x0409 + NDEBUG;%(PreprocessorDefinitions) + + + true + .\Debug_Unicode\inetc.bsc + + + true + true + wininet.lib;comctl32.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + true + false + libc.lib + DllMain + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/agent/installer/inetc/Contrib/Inetc/inetc.vcxproj.filters b/agent/installer/inetc/Contrib/Inetc/inetc.vcxproj.filters new file mode 100644 index 00000000000..6138b2a5b6c --- /dev/null +++ b/agent/installer/inetc/Contrib/Inetc/inetc.vcxproj.filters @@ -0,0 +1,52 @@ + + + + + {7803dcf0-655c-4f71-89dd-7fd695066a28} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {8edac42d-b9b9-469f-9864-3dbc65bf4365} + ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + {67a938b1-f16b-478b-81df-d0fd26de6d8a} + h;hpp;hxx;hm;inl + + + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + + + Resource Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/agent/installer/inetc/Contrib/Inetc/nsis_tchar.h b/agent/installer/inetc/Contrib/Inetc/nsis_tchar.h new file mode 100644 index 00000000000..3e02d12f70b --- /dev/null +++ b/agent/installer/inetc/Contrib/Inetc/nsis_tchar.h @@ -0,0 +1,229 @@ +/* + * nsis_tchar.h + * + * This file is a part of NSIS. + * + * Copyright (C) 1999-2013 Nullsoft and Contributors + * + * This software is provided 'as-is', without any express or implied + * warranty. + * + * For Unicode support by Jim Park -- 08/30/2007 + */ + +// Jim Park: Only those we use are listed here. + +#pragma once + +#ifdef _UNICODE + +#ifndef _T +#define __T(x) L ## x +#define _T(x) __T(x) +#define _TEXT(x) __T(x) +#endif + +#ifndef _TCHAR_DEFINED +#define _TCHAR_DEFINED +#if !defined(_NATIVE_WCHAR_T_DEFINED) && !defined(_WCHAR_T_DEFINED) +typedef unsigned short TCHAR; +#else +typedef wchar_t TCHAR; +#endif +#endif + + +// program +#define _tenviron _wenviron +#define __targv __wargv + +// printfs +#define _ftprintf fwprintf +#define _sntprintf _snwprintf +#if (defined(_MSC_VER) && (_MSC_VER<=1310)) || defined(__MINGW32__) +# define _stprintf swprintf +#else +# define _stprintf _swprintf +#endif +#define _tprintf wprintf +#define _vftprintf vfwprintf +#define _vsntprintf _vsnwprintf +#if defined(_MSC_VER) && (_MSC_VER<=1310) +# define _vstprintf vswprintf +#else +# define _vstprintf _vswprintf +#endif + +// scanfs +#define _tscanf wscanf +#define _stscanf swscanf + +// string manipulations +#define _tcscat wcscat +#define _tcschr wcschr +#define _tcsclen wcslen +#define _tcscpy wcscpy +#define _tcsdup _wcsdup +#define _tcslen wcslen +#define _tcsnccpy wcsncpy +#define _tcsncpy wcsncpy +#define _tcsrchr wcsrchr +#define _tcsstr wcsstr +#define _tcstok wcstok + +// string comparisons +#define _tcscmp wcscmp +#define _tcsicmp _wcsicmp +#define _tcsncicmp _wcsnicmp +#define _tcsncmp wcsncmp +#define _tcsnicmp _wcsnicmp + +// upper / lower +#define _tcslwr _wcslwr +#define _tcsupr _wcsupr +#define _totlower towlower +#define _totupper towupper + +// conversions to numbers +#define _tcstoi64 _wcstoi64 +#define _tcstol wcstol +#define _tcstoul wcstoul +#define _tstof _wtof +#define _tstoi _wtoi +#define _tstoi64 _wtoi64 +#define _ttoi _wtoi +#define _ttoi64 _wtoi64 +#define _ttol _wtol + +// conversion from numbers to strings +#define _itot _itow +#define _ltot _ltow +#define _i64tot _i64tow +#define _ui64tot _ui64tow + +// file manipulations +#define _tfopen _wfopen +#define _topen _wopen +#define _tremove _wremove +#define _tunlink _wunlink + +// reading and writing to i/o +#define _fgettc fgetwc +#define _fgetts fgetws +#define _fputts fputws +#define _gettchar getwchar + +// directory +#define _tchdir _wchdir + +// environment +#define _tgetenv _wgetenv +#define _tsystem _wsystem + +// time +#define _tcsftime wcsftime + +#else // ANSI + +#ifndef _T +#define _T(x) x +#define _TEXT(x) x +#endif + +#ifndef _TCHAR_DEFINED +#define _TCHAR_DEFINED +typedef char TCHAR; +#endif + +// program +#define _tenviron environ +#define __targv __argv + +// printfs +#define _ftprintf fprintf +#define _sntprintf _snprintf +#define _stprintf sprintf +#define _tprintf printf +#define _vftprintf vfprintf +#define _vsntprintf _vsnprintf +#define _vstprintf vsprintf + +// scanfs +#define _tscanf scanf +#define _stscanf sscanf + +// string manipulations +#define _tcscat strcat +#define _tcschr strchr +#define _tcsclen strlen +#define _tcscnlen strnlen +#define _tcscpy strcpy +#define _tcsdup _strdup +#define _tcslen strlen +#define _tcsnccpy strncpy +#define _tcsrchr strrchr +#define _tcsstr strstr +#define _tcstok strtok + +// string comparisons +#define _tcscmp strcmp +#define _tcsicmp _stricmp +#define _tcsncmp strncmp +#define _tcsncicmp _strnicmp +#define _tcsnicmp _strnicmp + +// upper / lower +#define _tcslwr _strlwr +#define _tcsupr _strupr + +#define _totupper toupper +#define _totlower tolower + +// conversions to numbers +#define _tcstol strtol +#define _tcstoul strtoul +#define _tstof atof +#define _tstoi atoi +#define _tstoi64 _atoi64 +#define _tstoi64 _atoi64 +#define _ttoi atoi +#define _ttoi64 _atoi64 +#define _ttol atol + +// conversion from numbers to strings +#define _i64tot _i64toa +#define _itot _itoa +#define _ltot _ltoa +#define _ui64tot _ui64toa + +// file manipulations +#define _tfopen fopen +#define _topen _open +#define _tremove remove +#define _tunlink _unlink + +// reading and writing to i/o +#define _fgettc fgetc +#define _fgetts fgets +#define _fputts fputs +#define _gettchar getchar + +// directory +#define _tchdir _chdir + +// environment +#define _tgetenv getenv +#define _tsystem system + +// time +#define _tcsftime strftime + +#endif + +// is functions (the same in Unicode / ANSI) +#define _istgraph isgraph +#define _istascii __isascii + +#define __TFILE__ _T(__FILE__) +#define __TDATE__ _T(__DATE__) +#define __TTIME__ _T(__TIME__) diff --git a/agent/installer/inetc/Contrib/Inetc/pluginapi.c b/agent/installer/inetc/Contrib/Inetc/pluginapi.c new file mode 100644 index 00000000000..5d878606ce2 --- /dev/null +++ b/agent/installer/inetc/Contrib/Inetc/pluginapi.c @@ -0,0 +1,294 @@ +#include + +#include "pluginapi.h" + +#ifdef _countof +#define COUNTOF _countof +#else +#define COUNTOF(a) (sizeof(a)/sizeof(a[0])) +#endif + +unsigned int g_stringsize; +stack_t **g_stacktop; +TCHAR *g_variables; + +// utility functions (not required but often useful) + +int NSISCALL popstring(TCHAR *str) +{ + stack_t *th; + if (!g_stacktop || !*g_stacktop) return 1; + th=(*g_stacktop); + if (str) lstrcpy(str,th->text); + *g_stacktop = th->next; + GlobalFree((HGLOBAL)th); + return 0; +} + +int NSISCALL popstringn(TCHAR *str, int maxlen) +{ + stack_t *th; + if (!g_stacktop || !*g_stacktop) return 1; + th=(*g_stacktop); + if (str) lstrcpyn(str,th->text,maxlen?maxlen:g_stringsize); + *g_stacktop = th->next; + GlobalFree((HGLOBAL)th); + return 0; +} + +void NSISCALL pushstring(const TCHAR *str) +{ + stack_t *th; + if (!g_stacktop) return; + th=(stack_t*)GlobalAlloc(GPTR,(sizeof(stack_t)+(g_stringsize)*sizeof(TCHAR))); + lstrcpyn(th->text,str,g_stringsize); + th->next=*g_stacktop; + *g_stacktop=th; +} + +TCHAR* NSISCALL getuservariable(const int varnum) +{ + if (varnum < 0 || varnum >= __INST_LAST) return NULL; + return g_variables+varnum*g_stringsize; +} + +void NSISCALL setuservariable(const int varnum, const TCHAR *var) +{ + if (var != NULL && varnum >= 0 && varnum < __INST_LAST) + lstrcpy(g_variables + varnum*g_stringsize, var); +} + +#ifdef _UNICODE +int NSISCALL PopStringA(char* ansiStr) +{ + wchar_t* wideStr = (wchar_t*) GlobalAlloc(GPTR, g_stringsize*sizeof(wchar_t)); + int rval = popstring(wideStr); + WideCharToMultiByte(CP_ACP, 0, wideStr, -1, ansiStr, g_stringsize, NULL, NULL); + GlobalFree((HGLOBAL)wideStr); + return rval; +} + +int NSISCALL PopStringNA(char* ansiStr, int maxlen) +{ + int realLen = maxlen ? maxlen : g_stringsize; + wchar_t* wideStr = (wchar_t*) GlobalAlloc(GPTR, realLen*sizeof(wchar_t)); + int rval = popstringn(wideStr, realLen); + WideCharToMultiByte(CP_ACP, 0, wideStr, -1, ansiStr, realLen, NULL, NULL); + GlobalFree((HGLOBAL)wideStr); + return rval; +} + +void NSISCALL PushStringA(const char* ansiStr) +{ + wchar_t* wideStr = (wchar_t*) GlobalAlloc(GPTR, g_stringsize*sizeof(wchar_t)); + MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, wideStr, g_stringsize); + pushstring(wideStr); + GlobalFree((HGLOBAL)wideStr); + return; +} + +void NSISCALL GetUserVariableW(const int varnum, wchar_t* wideStr) +{ + lstrcpyW(wideStr, getuservariable(varnum)); +} + +void NSISCALL GetUserVariableA(const int varnum, char* ansiStr) +{ + wchar_t* wideStr = getuservariable(varnum); + WideCharToMultiByte(CP_ACP, 0, wideStr, -1, ansiStr, g_stringsize, NULL, NULL); +} + +void NSISCALL SetUserVariableA(const int varnum, const char* ansiStr) +{ + if (ansiStr != NULL && varnum >= 0 && varnum < __INST_LAST) + { + wchar_t* wideStr = g_variables + varnum * g_stringsize; + MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, wideStr, g_stringsize); + } +} + +#else +// ANSI defs +int NSISCALL PopStringW(wchar_t* wideStr) +{ + char* ansiStr = (char*) GlobalAlloc(GPTR, g_stringsize); + int rval = popstring(ansiStr); + MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, wideStr, g_stringsize); + GlobalFree((HGLOBAL)ansiStr); + return rval; +} + +int NSISCALL PopStringNW(wchar_t* wideStr, int maxlen) +{ + int realLen = maxlen ? maxlen : g_stringsize; + char* ansiStr = (char*) GlobalAlloc(GPTR, realLen); + int rval = popstringn(ansiStr, realLen); + MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, wideStr, realLen); + GlobalFree((HGLOBAL)ansiStr); + return rval; +} + +void NSISCALL PushStringW(wchar_t* wideStr) +{ + char* ansiStr = (char*) GlobalAlloc(GPTR, g_stringsize); + WideCharToMultiByte(CP_ACP, 0, wideStr, -1, ansiStr, g_stringsize, NULL, NULL); + pushstring(ansiStr); + GlobalFree((HGLOBAL)ansiStr); +} + +void NSISCALL GetUserVariableW(const int varnum, wchar_t* wideStr) +{ + char* ansiStr = getuservariable(varnum); + MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, wideStr, g_stringsize); +} + +void NSISCALL GetUserVariableA(const int varnum, char* ansiStr) +{ + lstrcpyA(ansiStr, getuservariable(varnum)); +} + +void NSISCALL SetUserVariableW(const int varnum, const wchar_t* wideStr) +{ + if (wideStr != NULL && varnum >= 0 && varnum < __INST_LAST) + { + char* ansiStr = g_variables + varnum * g_stringsize; + WideCharToMultiByte(CP_ACP, 0, wideStr, -1, ansiStr, g_stringsize, NULL, NULL); + } +} +#endif + +// playing with integers + +INT_PTR NSISCALL nsishelper_str_to_ptr(const TCHAR *s) +{ + INT_PTR v=0; + if (*s == _T('0') && (s[1] == _T('x') || s[1] == _T('X'))) + { + s++; + for (;;) + { + int c=*(++s); + if (c >= _T('0') && c <= _T('9')) c-=_T('0'); + else if (c >= _T('a') && c <= _T('f')) c-=_T('a')-10; + else if (c >= _T('A') && c <= _T('F')) c-=_T('A')-10; + else break; + v<<=4; + v+=c; + } + } + else if (*s == _T('0') && s[1] <= _T('7') && s[1] >= _T('0')) + { + for (;;) + { + int c=*(++s); + if (c >= _T('0') && c <= _T('7')) c-=_T('0'); + else break; + v<<=3; + v+=c; + } + } + else + { + int sign=0; + if (*s == _T('-')) sign++; else s--; + for (;;) + { + int c=*(++s) - _T('0'); + if (c < 0 || c > 9) break; + v*=10; + v+=c; + } + if (sign) v = -v; + } + + return v; +} + +unsigned int NSISCALL myatou(const TCHAR *s) +{ + unsigned int v=0; + + for (;;) + { + unsigned int c=*s++; + if (c >= _T('0') && c <= _T('9')) c-=_T('0'); + else break; + v*=10; + v+=c; + } + return v; +} + +int NSISCALL myatoi_or(const TCHAR *s) +{ + int v=0; + if (*s == _T('0') && (s[1] == _T('x') || s[1] == _T('X'))) + { + s++; + for (;;) + { + int c=*(++s); + if (c >= _T('0') && c <= _T('9')) c-=_T('0'); + else if (c >= _T('a') && c <= _T('f')) c-=_T('a')-10; + else if (c >= _T('A') && c <= _T('F')) c-=_T('A')-10; + else break; + v<<=4; + v+=c; + } + } + else if (*s == _T('0') && s[1] <= _T('7') && s[1] >= _T('0')) + { + for (;;) + { + int c=*(++s); + if (c >= _T('0') && c <= _T('7')) c-=_T('0'); + else break; + v<<=3; + v+=c; + } + } + else + { + int sign=0; + if (*s == _T('-')) sign++; else s--; + for (;;) + { + int c=*(++s) - _T('0'); + if (c < 0 || c > 9) break; + v*=10; + v+=c; + } + if (sign) v = -v; + } + + // Support for simple ORed expressions + if (*s == _T('|')) + { + v |= myatoi_or(s+1); + } + + return v; +} + +INT_PTR NSISCALL popintptr() +{ + TCHAR buf[128]; + if (popstringn(buf,COUNTOF(buf))) + return 0; + return nsishelper_str_to_ptr(buf); +} + +int NSISCALL popint_or() +{ + TCHAR buf[128]; + if (popstringn(buf,COUNTOF(buf))) + return 0; + return myatoi_or(buf); +} + +void NSISCALL pushintptr(INT_PTR value) +{ + TCHAR buffer[30]; + wsprintf(buffer, sizeof(void*) > 4 ? _T("%Id") : _T("%d"), value); + pushstring(buffer); +} diff --git a/agent/installer/inetc/Contrib/Inetc/pluginapi.h b/agent/installer/inetc/Contrib/Inetc/pluginapi.h new file mode 100644 index 00000000000..d6541123b81 --- /dev/null +++ b/agent/installer/inetc/Contrib/Inetc/pluginapi.h @@ -0,0 +1,104 @@ +#ifndef ___NSIS_PLUGIN__H___ +#define ___NSIS_PLUGIN__H___ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "api.h" +#include "nsis_tchar.h" + +#ifndef NSISCALL +# define NSISCALL __stdcall +#endif + +#define EXDLL_INIT() { \ + g_stringsize=string_size; \ + g_stacktop=stacktop; \ + g_variables=variables; } + +typedef struct _stack_t { + struct _stack_t *next; + TCHAR text[1]; // this should be the length of string_size +} stack_t; + +enum +{ +INST_0, // $0 +INST_1, // $1 +INST_2, // $2 +INST_3, // $3 +INST_4, // $4 +INST_5, // $5 +INST_6, // $6 +INST_7, // $7 +INST_8, // $8 +INST_9, // $9 +INST_R0, // $R0 +INST_R1, // $R1 +INST_R2, // $R2 +INST_R3, // $R3 +INST_R4, // $R4 +INST_R5, // $R5 +INST_R6, // $R6 +INST_R7, // $R7 +INST_R8, // $R8 +INST_R9, // $R9 +INST_CMDLINE, // $CMDLINE +INST_INSTDIR, // $INSTDIR +INST_OUTDIR, // $OUTDIR +INST_EXEDIR, // $EXEDIR +INST_LANG, // $LANGUAGE +__INST_LAST +}; + +extern unsigned int g_stringsize; +extern stack_t **g_stacktop; +extern TCHAR *g_variables; + +void NSISCALL pushstring(const TCHAR *str); +void NSISCALL pushintptr(INT_PTR value); +#define pushint(v) pushintptr((INT_PTR)(v)) +int NSISCALL popstring(TCHAR *str); // 0 on success, 1 on empty stack +int NSISCALL popstringn(TCHAR *str, int maxlen); // with length limit, pass 0 for g_stringsize +INT_PTR NSISCALL popintptr(); +#define popint() ( (int) popintptr() ) +int NSISCALL popint_or(); // with support for or'ing (2|4|8) +INT_PTR NSISCALL nsishelper_str_to_ptr(const TCHAR *s); +#define myatoi(s) ( (int) nsishelper_str_to_ptr(s) ) // converts a string to an integer +unsigned int NSISCALL myatou(const TCHAR *s); // converts a string to an unsigned integer, decimal only +int NSISCALL myatoi_or(const TCHAR *s); // with support for or'ing (2|4|8) +TCHAR* NSISCALL getuservariable(const int varnum); +void NSISCALL setuservariable(const int varnum, const TCHAR *var); + +#ifdef _UNICODE +#define PopStringW(x) popstring(x) +#define PushStringW(x) pushstring(x) +#define SetUserVariableW(x,y) setuservariable(x,y) + +int NSISCALL PopStringA(char* ansiStr); +void NSISCALL PushStringA(const char* ansiStr); +void NSISCALL GetUserVariableW(const int varnum, wchar_t* wideStr); +void NSISCALL GetUserVariableA(const int varnum, char* ansiStr); +void NSISCALL SetUserVariableA(const int varnum, const char* ansiStr); + +#else +// ANSI defs + +#define PopStringA(x) popstring(x) +#define PushStringA(x) pushstring(x) +#define SetUserVariableA(x,y) setuservariable(x,y) + +int NSISCALL PopStringW(wchar_t* wideStr); +void NSISCALL PushStringW(wchar_t* wideStr); +void NSISCALL GetUserVariableW(const int varnum, wchar_t* wideStr); +void NSISCALL GetUserVariableA(const int varnum, char* ansiStr); +void NSISCALL SetUserVariableW(const int varnum, const wchar_t* wideStr); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif//!___NSIS_PLUGIN__H___ diff --git a/agent/installer/inetc/Contrib/Inetc/resource.h b/agent/installer/inetc/Contrib/Inetc/resource.h new file mode 100644 index 00000000000..d7fc835a648 --- /dev/null +++ b/agent/installer/inetc/Contrib/Inetc/resource.h @@ -0,0 +1,47 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by inetc.rc +// +#define IDC_SLOGIN 8 +#define IDC_PROGRESS 10 +#define IDC_SUBTEXT 11 +#define IDC_SPWD 11 +#define IDC_ICON1 12 +#define IDD_DIALOG1 101 +#define IDI_ICON1 102 +#define IDI_ICON2 103 +#define IDD_AUTH 104 +#define IDI_ICON3 105 +#define IDI_ICON4 106 +#define IDI_ICON5 107 +#define IDD_DIALOG2 108 +#define IDI_ICON6 109 +#define IDD_DIALOG3 110 +#define IDC_STATIC1 1001 +#define IDC_STATIC2 1002 +#define IDC_STATIC3 1003 +#define IDC_STATIC4 1004 +#define IDC_PROGRESS1 1005 +#define IDC_STATIC5 1006 +#define IDC_STATIC6 1007 +#define IDC_STATIC12 1008 +#define IDC_STATIC13 1009 +#define IDC_STATIC20 1009 +#define IDC_STATIC21 1010 +#define IDC_STATIC22 1011 +#define IDC_STATIC23 1012 +#define IDC_STATIC24 1013 +#define IDC_STATIC25 1014 +#define IDC_ELOGIN 1015 +#define IDC_EPWD 1016 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 111 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1018 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/agent/installer/inetc/Docs/Inetc/Readme.htm b/agent/installer/inetc/Docs/Inetc/Readme.htm new file mode 100644 index 00000000000..088a223f56c --- /dev/null +++ b/agent/installer/inetc/Docs/Inetc/Readme.htm @@ -0,0 +1,153 @@ +
+

Contents

+
    +
  • 1 Links +
  • 2 Description +
  • 3 Commands +
      +
    • 3.1 get +
    • 3.2 post +
    • 3.3 head +
    • 3.4 put +
    +
  • 4 Examples +
  • 5 Credits +
+
+ +

Links

+Download: http://nsis.sourceforge.net/Inetc_plug-in + +

Description

+Internet client plug-in for files download and upload. Based on the InetLoad plug-in. +Network implementation uses MS WinInet API, supports http/https and ftp protocols. +Plugin has better proxy support compare to NSISdl plug-in. Command line may include +few URL/File pairs to be transfered. If server or proxy login/password are not setten in the script, +displays IE-style authentication dialog (except silent mode). Plug-in supports 3 +"transfer in progress" display modes: +
    +
  • old NSISdl style - additional embedded progress bar and text on the INSTFILES page; +
  • POPUP dialog mode with detailed info; +
  • BANNER mode with simple popup window. +
+Plug-in recognizes Installer's Silent mode and this case hides any output (this feature +requires NSIS 2.03 or later). Program implements simple re-get functionality - host +reconnect and download from current position after short pause. While program depends on IE settings, +it changes current IE mode to online. NSISdl code fragment was used for progress bar displaying +in the "old style" mode. For ftp use "host/path" for file location relative to user's home dir and +"host//path" for absolute path. + +

Commands

+ +Plug-in DLL functions (entry points): get, post, head, put + +

get

+ +inetc::get [/PROXY IP:PORT] [/USERNAME PROXY_LOGIN /PASSWORD PROXY_PASSWD] [/NOCOOKIES] + [/NOPROXY] [/NOCANCEL] [/CONNECTTIMEOUT TO_SEC] [/RECEIVETIMEOUT TO_SEC] [/SILENT] [/WEAKSECURITY] + [/CAPTION TEXT] [/NOCOOKIES] [/RESUME RETRY_QUESTION] [/POPUP HOST_ALIAS | /BANNER TEXT] + [/CANCELTEXT CANCEL_TEXT] [/QUESTION CANCEL_QUESTION] [/USERAGENT USER_AGENT_TEXT] + [/HEADER HEADER_TEXT] [/TRANSLATE LANG_PARAMS] [/TOSTACK | /TOSTACKCONV] + URL1 local_file1 [URL2 local_file2 [...]] [/END] +

This call returns "OK" string if successful, error description string if failed (see included InetLoad.cpp file for a full set of status strings). Usage and result processing samples are included to the package. +

/PROXY - +Overwrites current proxy settings, not required in most cases. IE settings will be used by default. +

/USERNAME - +Proxy username (http only). +

/PASSWORD - +Proxy password (http only). For server (http/ftp) authentication it is possible to use URL encoded name and password, for example http://username:password@nsis.sourceforge.net. +

/NOPROXY - +Disables proxy settings for this connection (if any) +

/NOCANCEL - +Prevents download from being interrupted by user (locks Esc, Alt-F4, Cancel handling, removes sysmenu) +

/CONNECTTIMEOUT - +Sets INTERNET_OPTION_CONNECT_TIMEOUT, seconds, default - IE current parameter value. +

/RECEIVETIMEOUT - +Sets INTERNET_OPTION_RECEIVE_TIMEOUT, seconds, default - IE current parameter value. +

/SILENT - +Key hides plug-in' output (both popup dialog and embedded progress bar). Not required if 'SilentInstall silent' mode was defined in script (NSIS 2.03 or later). +

/WEAKSECURITY - +Ignore unknown and revoked certificates +

/RESUME - +On the permanent connection/transfer error instead of exit first displays message box with "resume download" question. Useful for dial-up connections and big files - allows user to restore connection and resume download. Default is "Your internet connection seems to have dropped out!\nPlease reconnect and click Retry to resume downloading...". +

/CAPTION - +Defines caption text for /BANNER mode, caption prefix (left of '-') for /POPUP mode and caption for RESUME MessageBox. Default is "InetLoad plug-in" if not set or "". 127 chars maximum. +

/POPUP - +This mode displays detailed download dialog instead of embedded progress bar. Also useful in .onInit function (i.e. not in Section). If HOST_ALIAS is not "", text will replace URL in the dialog - this allows to hide real URL (including password). +

/BANNER - +Displays simple popup dialog (MSI Banner mode) and sets dialog TEXT (up to 3 lines using $\n). +

/CANCELTEXT - +Text for the Cancel button in the NSISdl mode. Default is NSIS dialog Cancel button text (current lang). +

/QUESTION - +Text for the optional MessageBox if user tries to cancel download. If /QUESTION "" was used default +"Are you sure that you want to stop download?" will be substituted. +

/USERAGENT - +UserAgent http request header value. Default is "NSIS_Inetc (Mozilla)". 256 chars maximum. +

/HEADER - +Adds or replaces http request header. Common HEADER_TEXT format is "header: value". +

/NOCOOKIES - +Removes cookies from http request +

/TOSTACK - +Outputs the post/get/head response to the NSIS stack rather than to the file (specify an empty string for local_file1, local_file2 etc.) +

/TOSTACKCONV - +Outputs the post/get/head response to the NSIS stack while converting character encodings:
+ASCII -> Unicode for the Unicode plug-in build
+Unicode -> ASCII for the ASCII plug-in build +

/END - +Allows to limit plug-in stack reading (optional, required if you stores other vars in the stack). +

/TRANSLATE - +Allows translating plug-in text in the POPUP or NSISdl modes. 8 parameters both cases.
+ +NSISdl mode parameters:
+ /TRANSLATE downloading connecting second minute hour plural progress remaining
+With default values:
+ "Downloading %s" "Connecting ..." second minute hour s "%dkB (%d%%) of %dkB @ %d.%01dkB/s" "(%d %s%s remaining)"
+ +POPUP mode parameters:
+ /TRANSLATE url downloading connecting file_name received file_size remaining_time total_time
+With default values:
+ URL Downloading Connecting "File Name" Received "File Size" "Remaining Time" "Total Time"
+ +

post

+ +inetc::post TEXT2POST [/FILE] [/PROXY IP:PORT] [/NOPROXY] [/NOCANCEL] + [/USERNAME PROXY_LOGIN /PASSWORD PROXY_PASSWD] [/TIMEOUT INT_MS] [/SILENT] [/WEAKSECURITY] + [/CAPTION TEXT] [/POPUP | /BANNER TEXT] [/CANCELTEXT CANCEL_TEXT] + [/USERAGENT USER_AGENT_TEXT] [/TRANSLATE LANG_PARAMS] [/TOSTACK | /TOSTACKCONV] + URL1 local_file1 [URL2 local_file2 [...]] [/END] +

Sets POST http mode and defines text string to be used in the POST (http only). Disables auto re-get. No char replaces used (%20 and others). +If /FILE presents in command line, TEXT2POST is filename to be sent in POST request. Also 'Filename:' header will be added to HTTP headers. + +

head

+ +The same as get, but requests http headers only. Writes raw headers to file. + +

put

+ +inetc::put [/PROXY IP:PORT] [/USERNAME PROXY_LOGIN /PASSWORD PROXY_PASSWD] [/NOPROXY] + [/NOCANCEL] [/TIMEOUT INT_MS] [/SILENT] [/WEAKSECURITY] [/CAPTION TEXT] [/POPUP | /BANNER TEXT] + [/CANCELTEXT CANCEL_TEXT] [/USERAGENT USER_AGENT_TEXT] + [/TRANSLATE LANG_PARAMS] URL1 local_file1 [URL2 local_file2 [...]] [/END] +

Return value and parameters (if applicable) are the same as for previous entry point. + +

Examples

+
  inetc::put "http://dl.zvuki.ru/6306/mp3/12.mp3" "$EXEDIR\12.mp3" \
+     "ftp://dl.zvuki.ru/6306/mp3/11.mp3" "$EXEDIR\11.mp3"
+  Pop $0
+  inetc::put /BANNER "Cameron Diaz upload in progress..." \
+    "http://www.dreamgirlswallpaper.co.uk/fiveyearsonline/wallpaper/Cameron_Diaz/camerond09big.JPG" \
+    "$EXEDIR\cd.jpg"
+  Pop $0
+  StrCmp $0 "OK" dlok
+  MessageBox MB_OK|MB_ICONEXCLAMATION "http upload Error, click OK to abort installation" /SD IDOK
+  Abort
+dlok:
+  ...
+ +

Credits

+

Many thanks to Backland who offered a simple way to fix NSISdl mode crashes, added 'center parent' function, offers few nice design ideas and spent a lot of time testing the plug-in.

+
+

v1.0.4.4 by Stuart 'Afrow UK' Welch

+

v1.0.5.0..v1.0.5.2 by anders_k

+
+

See Contrib\inetc\inetc.cpp for changes.

diff --git a/agent/installer/inetc/Docs/Inetc/wiki.txt b/agent/installer/inetc/Docs/Inetc/wiki.txt new file mode 100644 index 00000000000..5aa0757a7a1 --- /dev/null +++ b/agent/installer/inetc/Docs/Inetc/wiki.txt @@ -0,0 +1,161 @@ +{{PageAuthor|Takhir}} + +== Links == + +Download:
+Inetc.zip
+ +[http://forums.winamp.com/showthread.php?threadid=198596 Forum thread] + +== Description == + +Internet client plug-in for files download and upload. Based on the InetLoad plug-in. Network implementation uses MS WinInet API, supports http/https and ftp protocols. Plugin has better proxy support compared to NSISdl plug-in. Command line may include few URL/File pairs to be transfered. If server or proxy login/password are not set in the script, it displays IE-style authentication dialog (except silent mode). Plug-in supports 3 "transfer in progress" display modes: + +# old NSISdl style - additional embedded progress bar and text on the INSTFILES page; +# POPUP dialog mode with detailed info; +# BANNER mode with simple popup window. + +Plug-in recognizes Installer's Silent mode and this case hides any output (this feature requires NSIS 2.03 or later). Program implements simple re-get functionality - host reconnect and download from current position after short pause. While program depends on IE settings, it changes current IE mode to online. NSISdl code fragment was used for progress bar displaying in the "old style" mode. +For ftp use "host/path" for file location relative to user's home dir and +"host//path" for absolute path. + +== Commands == + +Plug-in DLL functions (entry points): get, post, head, put + +=== get === + +inetc::get [/PROXY IP:PORT] [/USERNAME PROXY_LOGIN /PASSWORD PROXY_PASSWD] + [/NOPROXY] [/NOCANCEL] [/CONNECTTIMEOUT TO_SEC] [/RECEIVETIMEOUT TO_SEC] [/SILENT] [/WEAKSECURITY] + [/CAPTION TEXT] [/NOCOOKIES] [/RESUME RETRY_QUESTION] [/POPUP HOST_ALIAS | /BANNER TEXT] + [/CANCELTEXT CANCEL_TEXT] [/QUESTION CANCEL_QUESTION] [/USERAGENT USER_AGENT_TEXT] + [/HEADER HEADER_TEXT] [/TRANSLATE LANG_PARAMS] [/TOSTACK | /TOSTACKCONV] + URL1 local_file1 [URL2 local_file2 [...]] [/END] +This call returns "OK" string if successful, error description string if failed (see included InetLoad.cpp file for a full set of status strings). Usage and result processing samples are included to the package. + +; /PROXY +: Overwrites current proxy settings, not required in most cases. IE settings will be used by default. + +; /USERNAME +: Proxy username (http only). + +; /PASSWORD +: Proxy password (http only). For server (http/ftp) authentication it is possible to use URL encoded name and password, for example http://username:password@nsis.sourceforge.net. + +; /NOPROXY +: Disables proxy settings for this connection (if any) + +; /NOCANCEL +: Prevents download from being interrupted by user (locks Esc, Alt-F4, Cancel handling) + +; /CONNECTTIMEOUT - +:Sets INTERNET_OPTION_CONNECT_TIMEOUT, seconds, default - IE current parameter value. + +; /RECEIVETIMEOUT - +:Sets INTERNET_OPTION_RECEIVE_TIMEOUT, seconds, default - IE current parameter value. + +; /SILENT +: Key hides plug-in' output (both popup dialog and embedded progress bar). Not required if 'SilentInstall silent' mode was defined in script (NSIS 2.03 or later). + +; /WEAKSECURITY +: Ignore unknown and revoked certificates + +; /RESUME +: On the permanent connection/transfer error instead of exit first displays message box with "resume download" question. Useful for dial-up connections and big files - allows user to restore connection and resume download. Default is "Your internet connection seems to have dropped out!\nPlease reconnect and click Retry to resume downloading...". + +; /CAPTION +: Defines caption text for /BANNER mode, caption prefix (left of '-') for /POPUP mode and caption for RESUME MessageBox. Default is "InetLoad plug-in" if not set or "". + +; /POPUP +: This mode displays detailed download dialog instead of embedded progress bar. Also useful in .onInit function (i.e. not in Section). If HOST_ALIAS is not "", text will replace URL in the dialog - this allows to hide real URL (including password). + +; /BANNER +: Displays simple popup dialog (MSI Banner mode) and sets dialog TEXT (up to 3 lines using $\n). + +; /CANCELTEXT +: Text for the Cancel button in the NSISdl mode. Default is NSIS dialog Cancel button text (current lang). + +; /QUESTION +: Text for the optional MessageBox if user tries to cancel download. If /QUESTION "" was used default "Are you sure that you want to stop download?" will be substituted. + +; /USERAGENT +: UserAgent http request header value. Default is "NSIS_Inetc (Mozilla)". + +; /HEADER +: Adds or replaces http request header. Common HEADER_TEXT format is "header: value". + +; /NOCOOKIES +: Removes cookies from http request + +; /TOSTACK +: Outputs the post/get/head response to the NSIS stack rather than to the file (specify an empty string for local_file1, local_file2 etc.) + +; /TOSTACKCONV +: Outputs the post/get/head response to the NSIS stack while converting character encodings: +: ASCII -> Unicode for the Unicode plug-in build +: Unicode -> ASCII for the ASCII plug-in build + +; /END +: Allows to limit plug-in stack reading (optional, required if you stores other vars in the stack). + +; /TRANSLATE +: Allows translating plug-in text in the POPUP or "old style" (NSISdl) modes (see Readme for parameters). In the BANNER mode text is also customizable. + +=== post === + +inetc::post TEXT2POST [/PROXY IP:PORT] [/USERNAME PROXY_LOGIN /PASSWORD PROXY_PASSWD] + [/NOPROXY] [/NOCANCEL] [/CONNECTTIMEOUT TO_SEC] [/RECEIVETIMEOUT TO_SEC] [/SILENT] [/WEAKSECURITY] + [/FILE] [/CAPTION TEXT] [/NOCOOKIES] [/POPUP HOST_ALIAS | /BANNER TEXT] + [/CANCELTEXT CANCEL_TEXT] [/USERAGENT USER_AGENT_TEXT] [/TRANSLATE LANG_PARAMS] + [/TOSTACK | /TOSTACKCONV] + URL1 local_file1 [URL2 local_file2 [...]] [/END] +Sets POST http mode and defines text string or file name to be used in the POST (http only). Disables auto re-get. No char replaces used (%20 and others). /FILE option allows to send TEXT2POST file content to server, additional 'Filename:' header added to request this case. + +=== head === + +The same as get, but requests http headers only. Writes raw headers to file. + +=== put === + +inetc::put [/PROXY IP:PORT] [/USERNAME PROXY_LOGIN /PASSWORD PROXY_PASSWD] [/NOPROXY] + [/NOCANCEL] [/CONNECTTIMEOUT TO_SEC] [/RECEIVETIMEOUT TO_SEC] [/SILENT] [/WEAKSECURITY] [/CAPTION TEXT] + [/POPUP HOST_ALIAS | /BANNER TEXT] [/CANCELTEXT CANCEL_TEXT] [/USERAGENT USER_AGENT_TEXT] + [/TRANSLATE LANG_PARAMS] [/NOCOOKIES] + URL1 local_file1 [URL2 local_file2 [...]] [/END] +Return value and parameters (if applicable) are the same as for previous entry point. + +== Examples == + + +inetc::put "http://dl.zvuki.ru/6306/mp3/12.mp3" "$EXEDIR\12.mp3" \ + "ftp://dl.zvuki.ru/6306/mp3/11.mp3" "$EXEDIR\11.mp3" +Pop $0 + + + +inetc::put /BANNER "Cameron Diaz upload in progress..." \ +"http://www.dreamgirlswallpaper.co.uk/fiveyearsonline/wallpaper/Cameron_Diaz/camerond09big.JPG" \ +"$EXEDIR\cd.jpg" + Pop $0 + StrCmp $0 "OK" dlok + MessageBox MB_OK|MB_ICONEXCLAMATION "http upload Error, click OK to abort installation" /SD IDOK + Abort +dlok: + ... + + + +; Following attribute also can restore installer Window +; BGGradient 000000 000080 FFFFFF + +== Credits == + +

Many thanks to Backland who offered a simple way to fix NSISdl mode crashes, added 'center parent' function, offers few nice design ideas and spent a lot of time testing the plug-in.

+
+

v1.0.4.4 by Stuart 'Afrow UK' Welch

+

v1.0.5.0..v1.0.5.2 by anders_k

+
+

See Contrib\inetc\inetc.cpp for changes.

+ + +[[Category:Plugins]] diff --git a/agent/installer/inetc/Examples/Inetc/Example.nsi b/agent/installer/inetc/Examples/Inetc/Example.nsi new file mode 100644 index 00000000000..963d5f47f2a --- /dev/null +++ b/agent/installer/inetc/Examples/Inetc/Example.nsi @@ -0,0 +1,54 @@ + +;-------------------------------- +; General Attributes + +Name "Inetc plug-in Test" +OutFile "inetc.exe" +;SilentInstall silent +RequestExecutionLevel user + + +;-------------------------------- +;Interface Settings + + !include "MUI2.nsh" + !define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install-colorful.ico" + !insertmacro MUI_PAGE_WELCOME + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_LANGUAGE "English" + +;SetFont 14 + +;-------------------------------- +;Installer Sections + +Section "Dummy Section" SecDummy + + SetDetailsView hide + +; two files download, popup mode + inetc::get /caption "2003-2004 reports" /popup "" "http://ineum.narod.ru/spr_2003.htm" "$EXEDIR\spr3.htm" "http://ineum.narod.ru/spr_2004.htm" "$EXEDIR\spr4.htm" /end + Pop $0 # return value = exit code, "OK" means OK + +; single file, NSISdl-style embedded progress bar with specific cancel button text + inetc::get /caption "2005 report" /canceltext "interrupt!" "http://ineum.narod.ru/spr_2005.htm" "$EXEDIR\spr5.htm" /end + Pop $1 # return value = exit code, "OK" means OK + +; banner with 2 text lines and disabled Cancel button + inetc::get /caption "2006 report" /banner "Banner mode with /nocancel option setten$\nSecond Line" /nocancel "http://ineum.narod.ru/spr_2006.htm" "$EXEDIR\spr6.htm" /end + Pop $2 # return value = exit code, "OK" means OK + + MessageBox MB_OK "Download Status: $0, $1, $2" +SectionEnd + + +;-------------------------------- +;Installer Functions + +Function .onInit + +; plug-in auto-recognizes 'no parent dlg' in onInit and works accordingly +; inetc::head /RESUME "Network error. Retry?" "http://ineum.narod.ru/spr_2003.htm" "$EXEDIR\spr3.txt" +; Pop $4 + +FunctionEnd \ No newline at end of file diff --git a/agent/installer/inetc/Examples/Inetc/auth_dlg.nsi b/agent/installer/inetc/Examples/Inetc/auth_dlg.nsi new file mode 100644 index 00000000000..ac845237621 --- /dev/null +++ b/agent/installer/inetc/Examples/Inetc/auth_dlg.nsi @@ -0,0 +1,32 @@ + +;-------------------------------- +; General Attributes + +Name "Inetc http auth Test" +OutFile "auth_dlg.exe" +RequestExecutionLevel user + + +;-------------------------------- +;Interface Settings + + !include "MUI2.nsh" + !define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install-colorful.ico" + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_LANGUAGE "English" + + +;-------------------------------- +;Installer Sections + +Section "Dummy Section" SecDummy + +; Displays IE auth dialog. +; Both server and proxy auth. +; Please test this with your own link. + + inetc::get "http://www.cnt.ru/personal" "$EXEDIR\auth.html" + Pop $0 # return value = exit code, "OK" if OK + MessageBox MB_OK "Download Status: $0" + +SectionEnd diff --git a/agent/installer/inetc/Examples/Inetc/ftp_auth.nsi b/agent/installer/inetc/Examples/Inetc/ftp_auth.nsi new file mode 100644 index 00000000000..ef3ff2a92b1 --- /dev/null +++ b/agent/installer/inetc/Examples/Inetc/ftp_auth.nsi @@ -0,0 +1,32 @@ + +;-------------------------------- +; General Attributes + +Name "Inetc ftp authentication Test" +OutFile "ftp_auth.exe" +RequestExecutionLevel user + + +;-------------------------------- +;Interface Settings + + !include "MUI2.nsh" + !define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install-colorful.ico" + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_LANGUAGE "English" + + +;-------------------------------- +;Installer Sections + +Section "Dummy Section" SecDummy + +; use your own URL and login@pwd. Password hidden from user with /popup "ALIAS" + + inetc::get /caption "service pack download" /popup "ftp://localhost/" "ftp://login:pwd@localhost/W2Ksp3.exe" "$EXEDIR\sp3.exe" +; inetc::put /caption "service pack upload" /popup "" "ftp://login:pwd@localhost/W2Ksp3.bu.exe" "$EXEDIR\sp3.exe" + Pop $0 # return value = exit code, "OK" if OK + MessageBox MB_OK "Download Status: $0" + +SectionEnd + diff --git a/agent/installer/inetc/Examples/Inetc/head.nsi b/agent/installer/inetc/Examples/Inetc/head.nsi new file mode 100644 index 00000000000..234a48dbf77 --- /dev/null +++ b/agent/installer/inetc/Examples/Inetc/head.nsi @@ -0,0 +1,30 @@ + +;-------------------------------- +; General Attributes + +Name "Inetc Head Test" +OutFile "head.exe" +RequestExecutionLevel user + + +;-------------------------------- +;Interface Settings + + !include "MUI2.nsh" + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_LANGUAGE "English" + + +;-------------------------------- +;Installer Sections + +Section "Dummy Section" SecDummy + + DetailPrint "New version check out (internet connection)" + inetc::head /silent "http://ineum.narod.ru/spr_2006.htm" "$EXEDIR\head.txt" + Pop $0 # return value = exit code, "OK" if OK + MessageBox MB_OK "Download Status: $0" + +SectionEnd + + diff --git a/agent/installer/inetc/Examples/Inetc/headers.nsi b/agent/installer/inetc/Examples/Inetc/headers.nsi new file mode 100644 index 00000000000..b8725d21614 --- /dev/null +++ b/agent/installer/inetc/Examples/Inetc/headers.nsi @@ -0,0 +1,32 @@ + +;-------------------------------- +; General Attributes + +Name "Headers Test" +OutFile "headers.exe" +RequestExecutionLevel user + + +;-------------------------------- +;Interface Settings + + !include "MUI2.nsh" + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_LANGUAGE "English" + + + +;-------------------------------- +;Installer Sections + +Section "Dummy Section" SecDummy + +; additional headers. Sample php returns raw headers + inetc::get /useragent "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1)" /header "SOAPAction: urn:anonOutInOpe" "http://localhost/headers.php" "$EXEDIR\headers.html" + Pop $0 + + MessageBox MB_OK "Download Status: $0" + +SectionEnd + + diff --git a/agent/installer/inetc/Examples/Inetc/headers.php b/agent/installer/inetc/Examples/Inetc/headers.php new file mode 100644 index 00000000000..e33b0d8ed1f --- /dev/null +++ b/agent/installer/inetc/Examples/Inetc/headers.php @@ -0,0 +1,7 @@ + $value) { + echo "$header: $value
\n"; +} +?> \ No newline at end of file diff --git a/agent/installer/inetc/Examples/Inetc/https.nsi b/agent/installer/inetc/Examples/Inetc/https.nsi new file mode 100644 index 00000000000..72d91287593 --- /dev/null +++ b/agent/installer/inetc/Examples/Inetc/https.nsi @@ -0,0 +1,27 @@ + +;-------------------------------- +; General Attributes + +Name "Inetc https Test" +OutFile "https.exe" +RequestExecutionLevel user + + +;-------------------------------- +;Interface Settings + + !include "MUI2.nsh" + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_LANGUAGE "English" + + +;-------------------------------- +;Installer Sections + +Section "Dummy Section" SecDummy + + inetc::get /POPUP "" /CAPTION "bending_property_demo.zip" "https://secure.codeproject.com/cs/miscctrl/bending_property/bending_property_src.zip" "$EXEDIR\bending_property_src.zip" + Pop $0 # return value = exit code, "OK" if OK + MessageBox MB_OK "Download Status: $0" + +SectionEnd diff --git a/agent/installer/inetc/Examples/Inetc/inetc_local.nsi b/agent/installer/inetc/Examples/Inetc/inetc_local.nsi new file mode 100644 index 00000000000..1d3373bc6b3 --- /dev/null +++ b/agent/installer/inetc/Examples/Inetc/inetc_local.nsi @@ -0,0 +1,81 @@ + +;-------------------------------- +; General Attributes + +Name "Inetc Local Test" +OutFile "inetc_local.exe" +RequestExecutionLevel user + + +;-------------------------------- +;Interface Settings + + !include "MUI2.nsh" + !define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install-colorful.ico" + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_LANGUAGE "English" + + +;-------------------------------- +;Installer Sections + +Section "Dummy Section" SecDummy + + +; PUT test + +; FTP requires anonymous access in sample below. +; HTTP sample put.php included to package. Stores test.jpg as m2.bmp +; check server files present after upload + + inetc::put "http://localhost/put.php" "$EXEDIR\test.jpg" + Pop $0 + + inetc::put "ftp://localhost/test.jpg" "$EXEDIR\test.jpg" +; not anonymous format +; inetc::put "ftp://login:password@localhost/test.jpg" "$EXEDIR\test.jpg" + Pop $1 + + DetailPrint "PUT: HTTP $0, FTP $1 (verify server files)" + + +; POST test + +; HTTP sample post.php and post_form.htm (to compare results) included + + inetc::post "login=ami&passwd=333" "http://localhost/post.php?lg=iam&pw=44" "$EXEDIR\post_reply.htm" + Pop $2 + + DetailPrint "POST: $2 (post_reply.htm)" + + +; HEAD test + +; uses uploaded earlier test.jpg + + inetc::head /silent "http://localhost/m2.bmp" "$EXEDIR\head.txt" + Pop $3 + + DetailPrint "HEAD: $3 (head.txt)" + + +; GET test + +; 2 files download in nsisdl mode + inetc::get "http://localhost/m2.bmp" "$EXEDIR\get1.jpg" "http://localhost/m2.bmp" "$EXEDIR\get2.jpg" + Pop $4 + + inetc::get /popup "Localhost:GET with Popup" "http://localhost/m2.bmp" "$EXEDIR\get3.jpg" + Pop $5 + + inetc::get /banner "Local Test GET with Banner" "http://localhost/m2.bmp" "$EXEDIR\get4.jpg" + Pop $6 + + inetc::get /silent "ftp://localhost/test.jpg" "$EXEDIR\get5.jpg" + Pop $7 + + DetailPrint "GET: NSISDL $4, POPUP $5, BANNER $6, FTP $7 (get1-5.jpg)" + + SetDetailsView show + +SectionEnd diff --git a/agent/installer/inetc/Examples/Inetc/post.nsi b/agent/installer/inetc/Examples/Inetc/post.nsi new file mode 100644 index 00000000000..79b6773608d --- /dev/null +++ b/agent/installer/inetc/Examples/Inetc/post.nsi @@ -0,0 +1,31 @@ + +;-------------------------------- +; General Attributes + +Name "Inetc Post Test" +OutFile "post.exe" +RequestExecutionLevel user + + +;-------------------------------- +;Interface Settings + + !include "MUI2.nsh" + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_LANGUAGE "English" + + +;-------------------------------- +;Installer Sections + +Section "Dummy Section" SecDummy + +; this is my LAN sample, use your own URL for tests. Sample post.php included + + inetc::post "login=ami&passwd=333" "http://localhost/post.php?lg=iam&pw=44" "$EXEDIR\post_reply.htm" + Pop $0 # return value = exit code, "OK" if OK + MessageBox MB_OK "Download Status: $0" + +SectionEnd + + diff --git a/agent/installer/inetc/Examples/Inetc/post.php b/agent/installer/inetc/Examples/Inetc/post.php new file mode 100644 index 00000000000..f6a89496412 --- /dev/null +++ b/agent/installer/inetc/Examples/Inetc/post.php @@ -0,0 +1,13 @@ + + + + +"; +echo "post.passwd=".$_POST['passwd']."
"; +echo "get.lg=".$_GET['lg']."
"; +echo "get.pw=".$_GET['pw']."
"; +?> + + + diff --git a/agent/installer/inetc/Examples/Inetc/post_file.nsi b/agent/installer/inetc/Examples/Inetc/post_file.nsi new file mode 100644 index 00000000000..2fde0a9285f --- /dev/null +++ b/agent/installer/inetc/Examples/Inetc/post_file.nsi @@ -0,0 +1,31 @@ + +;-------------------------------- +; General Attributes + +Name "Inetc Post Test" +OutFile "post_file.exe" +RequestExecutionLevel user + + +;-------------------------------- +;Interface Settings + + !include "MUI2.nsh" + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_LANGUAGE "English" + + +;-------------------------------- +;Installer Sections + +Section "Dummy Section" SecDummy + +; this is my LAN sample, use your own URL for tests. Sample post.php included + + inetc::post "$EXEDIR\inetc.cpp" /file "http://localhost/post_file.php" "$EXEDIR\post_file.htm" + Pop $0 # return value = exit code, "OK" if OK + MessageBox MB_OK "Download Status: $0" + +SectionEnd + + diff --git a/agent/installer/inetc/Examples/Inetc/post_file.php b/agent/installer/inetc/Examples/Inetc/post_file.php new file mode 100644 index 00000000000..07ab4fbf287 --- /dev/null +++ b/agent/installer/inetc/Examples/Inetc/post_file.php @@ -0,0 +1,10 @@ + $value) { + echo "$header: $value
\n"; +} +echo "new
"; +foreach ($_FILES as $key => $value) echo $key . "<>" . $value . "
\n"; +echo file_get_contents('php://input'); +?> \ No newline at end of file diff --git a/agent/installer/inetc/Examples/Inetc/post_form.html b/agent/installer/inetc/Examples/Inetc/post_form.html new file mode 100644 index 00000000000..046d605337f --- /dev/null +++ b/agent/installer/inetc/Examples/Inetc/post_form.html @@ -0,0 +1,18 @@ + + +Registration form for post.php test + + +This form sends POST request to server. It was interesting to compare server echo
+reply (by included post.php) for this form and InetLoad plug-in - in my
+tests server did not see any difference between them :)
+
+ +
+
+ + +
+ + + diff --git a/agent/installer/inetc/Examples/Inetc/put.nsi b/agent/installer/inetc/Examples/Inetc/put.nsi new file mode 100644 index 00000000000..582f2653474 --- /dev/null +++ b/agent/installer/inetc/Examples/Inetc/put.nsi @@ -0,0 +1,31 @@ + +;-------------------------------- +; General Attributes + +Name "Inetc Test" +OutFile "put.exe" +RequestExecutionLevel user + + +;-------------------------------- +;Interface Settings + + !include "MUI2.nsh" + !define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install-colorful.ico" + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_LANGUAGE "English" + + +;-------------------------------- +;Installer Sections + +Section "Dummy Section" SecDummy + +; this is my LAN sample, use your own URL for tests. Login/pwd hidden from user. Sample put.php (for http request) included + + inetc::put "http://localhost/put.php" "$EXEDIR\test.jpg" +; inetc::put /POPUP "ftp://localhost/" /CAPTION "my local ftp upload" "ftp://localhost/test.jpg" "$EXEDIR\test.jpg" + Pop $0 + MessageBox MB_OK "Upload Status: $0" + +SectionEnd diff --git a/agent/installer/inetc/Examples/Inetc/put.php b/agent/installer/inetc/Examples/Inetc/put.php new file mode 100644 index 00000000000..7bb2bf526dd --- /dev/null +++ b/agent/installer/inetc/Examples/Inetc/put.php @@ -0,0 +1,19 @@ + diff --git a/agent/installer/inetc/Examples/Inetc/recursive.nsi b/agent/installer/inetc/Examples/Inetc/recursive.nsi new file mode 100644 index 00000000000..925080df34e --- /dev/null +++ b/agent/installer/inetc/Examples/Inetc/recursive.nsi @@ -0,0 +1,65 @@ +Name "Inetc Recursive Dir Upload Test" +OutFile "recursive.exe" +RequestExecutionLevel user + +!include "MUI2.nsh" +!insertmacro MUI_PAGE_INSTFILES +!insertmacro MUI_LANGUAGE "English" +!include "FileFunc.nsh" +!insertmacro GetFileAttributes + +var url +var path + +Function dirul + + Push $0 ; search handle + Push $1 ; file name + Push $2 ; attributes + + FindFirst $0 $1 "$path\*" +loop: + StrCmp $1 "" done + ${GetFileAttributes} "$path\$1" DIRECTORY $2 + IntCmp $2 1 isdir +retry: + Inetc::put $url/$1 "$path\$1" /end + Pop $2 + DetailPrint "$2 $path\$1" + StrCmp $2 "OK" cont + MessageBox MB_YESNO "$path\$1 file upload failed. Retry?" IDYES retry + Abort "terminated by user" + Goto cont +isdir: + StrCmp $1 . cont + StrCmp $1 .. cont + Push $path + Push $url + StrCpy $path "$path\$1" + StrCpy $url "$url/$1" + Call dirul + Pop $url + Pop $path +cont: + FindNext $0 $1 + Goto loop +done: + FindClose $0 + + Pop $2 + Pop $1 + Pop $0 + +FunctionEnd + + +Section "Dummy Section" SecDummy + + SetDetailsView hide + StrCpy $path "$EXEDIR" +; put is dir in the user's ftp home, use //put for root-relative path + StrCpy $url ftp://takhir:pwd@localhost/put + Call dirul + SetDetailsView show + +SectionEnd diff --git a/agent/installer/inetc/Examples/Inetc/redirect.nsi b/agent/installer/inetc/Examples/Inetc/redirect.nsi new file mode 100644 index 00000000000..64c952ab2f5 --- /dev/null +++ b/agent/installer/inetc/Examples/Inetc/redirect.nsi @@ -0,0 +1,31 @@ + +;-------------------------------- +; General Attributes + +Name "Redirect Test" +OutFile "redirect.exe" +RequestExecutionLevel user + + +;-------------------------------- +;Interface Settings + + !include "MUI2.nsh" + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_LANGUAGE "English" + + +;-------------------------------- +;Installer Sections + +Section "Dummy Section" SecDummy + + SetDetailsView hide + + inetc::get "http://localhost/redirect.php" "$EXEDIR\redirect.htm" /end + Pop $1 + + MessageBox MB_OK "Download Status: $1" + +SectionEnd + diff --git a/agent/installer/inetc/Examples/Inetc/redirect.php b/agent/installer/inetc/Examples/Inetc/redirect.php new file mode 100644 index 00000000000..afe455283f4 --- /dev/null +++ b/agent/installer/inetc/Examples/Inetc/redirect.php @@ -0,0 +1,6 @@ + diff --git a/agent/installer/inetc/Examples/Inetc/timeout.nsi b/agent/installer/inetc/Examples/Inetc/timeout.nsi new file mode 100644 index 00000000000..5a489ba35e3 --- /dev/null +++ b/agent/installer/inetc/Examples/Inetc/timeout.nsi @@ -0,0 +1,32 @@ + +;-------------------------------- +; General Attributes + +Name "Timeout Test" +OutFile "to.exe" +RequestExecutionLevel user + + +;-------------------------------- +;Interface Settings + + !include "MUI2.nsh" + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_LANGUAGE "English" + + + +;-------------------------------- +;Installer Sections + +Section "Dummy Section" SecDummy + +; additional headers. Sample php returns raw headers + inetc::get /receivetimeout 12 "http://localhost/to.php" "$EXEDIR\to.html" + Pop $0 + + MessageBox MB_OK "Download Status: $0" + +SectionEnd + + diff --git a/agent/installer/inetc/Examples/Inetc/tostack.nsi b/agent/installer/inetc/Examples/Inetc/tostack.nsi new file mode 100644 index 00000000000..f5ed4435ab8 --- /dev/null +++ b/agent/installer/inetc/Examples/Inetc/tostack.nsi @@ -0,0 +1,32 @@ + +;-------------------------------- +; General Attributes + +Name "Inetc To Stack Test" +OutFile "ToStack.exe" +RequestExecutionLevel user + + +;-------------------------------- +;Interface Settings + + !include "MUI2.nsh" + !define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install-colorful.ico" + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_LANGUAGE "English" + + +;-------------------------------- +;Installer Sections + +Section "Dummy Section" SecDummy + + inetc::get /TOSTACK "http://www.google.com" "" /END + Pop $0 # return value = exit code, "OK" if OK + MessageBox MB_OK "Download Status: $0" + Pop $0 # return text + StrLen $1 $0 + MessageBox MB_OK "Download Length: $1" + MessageBox MB_OK "$0" + +SectionEnd diff --git a/agent/installer/inetc/Examples/Inetc/translate.nsi b/agent/installer/inetc/Examples/Inetc/translate.nsi new file mode 100644 index 00000000000..c09a7706f98 --- /dev/null +++ b/agent/installer/inetc/Examples/Inetc/translate.nsi @@ -0,0 +1,33 @@ + +;-------------------------------- +; General Attributes + +Name "Inetc Translate Test" +OutFile "Translate.exe" +RequestExecutionLevel user + + +;-------------------------------- +;Interface Settings + + !include "MUI2.nsh" + !define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install-colorful.ico" + !insertmacro MUI_PAGE_WELCOME + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_PAGE_FINISH + !insertmacro MUI_LANGUAGE "Russian" + + +;-------------------------------- +;Installer Sections + +Section "Dummy Section" SecDummy + +; This is russian variant. See Readme.txt for a list of parameters. +; Use LangStrings as TRANSLATE parameters for multilang options + + inetc::load /POPUP "" /CAPTION "Ôàéë ãàëåðåè" /TRANSLATE "URL" "Çàãðóçêà" "Ïîïûòêà ñîåäèíåíèÿ" "Èìÿ ôàéëà" Ïîëó÷åíî "Ðàçìåð" "Îñòàëîñü" "Ïðîøëî" "http://ineum.narod.ru/g06s.htm" "$EXEDIR\g06s.htm" + Pop $0 # return value = exit code, "OK" if OK + MessageBox MB_OK "Download Status: $0" + +SectionEnd diff --git a/agent/installer/inetc/Plugins/amd64-unicode/INetC.dll b/agent/installer/inetc/Plugins/amd64-unicode/INetC.dll new file mode 100644 index 00000000000..2427cfd4428 Binary files /dev/null and b/agent/installer/inetc/Plugins/amd64-unicode/INetC.dll differ diff --git a/agent/installer/inetc/Plugins/x86-ansi/INetC.dll b/agent/installer/inetc/Plugins/x86-ansi/INetC.dll new file mode 100644 index 00000000000..d01dc48a6b1 Binary files /dev/null and b/agent/installer/inetc/Plugins/x86-ansi/INetC.dll differ diff --git a/agent/installer/inetc/Plugins/x86-unicode/INetC.dll b/agent/installer/inetc/Plugins/x86-unicode/INetC.dll new file mode 100644 index 00000000000..d867f8c2e8e Binary files /dev/null and b/agent/installer/inetc/Plugins/x86-unicode/INetC.dll differ diff --git a/agent/installer/inetc/build_msvc.cmd b/agent/installer/inetc/build_msvc.cmd new file mode 100644 index 00000000000..f34c717db45 --- /dev/null +++ b/agent/installer/inetc/build_msvc.cmd @@ -0,0 +1,26 @@ +@echo off +setlocal +set Name=INetC +set DistRoot=. +set SrcRoot=%DistRoot%\Contrib\%Name% +set BaseCL=/GL /LD /W3 /O1 /Osy /GF /Gz /GS- /GR- /Zl /D_VC_NODEFAULTLIB +set BaseLINK=/LTCG /DLL /OPT:REF /OPT:ICF,99 /MERGE:.rdata=.text /OPT:NOWIN98 /NODEFAULTLIB kernel32.lib user32.lib advapi32.lib comctl32.lib wininet.lib +set Targets=x86-ansi x86-unicode +(>nul (( 2>&1 call cl "/?" )|find /I "AMD64"))&&(set Targets=amd64-unicode) +for %%A in (%Targets%) do (call :B %%A) +@goto :EOF + + +:B targ +set DEF=/D___NSISPLUGIN +((echo %1|find /I "unicode")>nul)&&set DEF=%DEF% /DUNICODE /D_UNICODE +set CL=%BaseCL% %DEF% /Gy +set LINK=%BaseLINK% +for %%B in (%SrcRoot%\*.rc) do call RC /R /FO"%DistRoot%\%%~nB.res" "%%B" +for %%A in (c cpp cxx) do for %%B in (%SrcRoot%\*.%%A) do ( + if exist "%DistRoot%\%%~nB.obj" del "%DistRoot%\%%~nB.obj" + call CL /c %%B /Fe"%DistRoot%\%Name%" + ) +md "%DistRoot%\Plugins\%1" 2>nul +call LINK /NOLOGO /OUT:"%DistRoot%\Plugins\%1\%Name%.dll" /PDB:"%DistRoot%\%Name%-%1" "%DistRoot%\*.obj" "%DistRoot%\*.res" +@goto :EOF diff --git a/agent/installer/ns_json/Contrib/nsJSON/ConsoleApp/ConsoleApp.vcxproj b/agent/installer/ns_json/Contrib/nsJSON/ConsoleApp/ConsoleApp.vcxproj new file mode 100644 index 00000000000..acdf9435a07 --- /dev/null +++ b/agent/installer/ns_json/Contrib/nsJSON/ConsoleApp/ConsoleApp.vcxproj @@ -0,0 +1,141 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {6ECB05AC-F1A5-41F9-8880-431EEB8E2D7D} + ConsoleApp + 8.1 + + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + false + + + false + + + + Level3 + Disabled + true + + + + + Debug + + + + + Level3 + Disabled + true + + + + + Debug + + + + + Level3 + MaxSpeed + true + true + false + + + true + true + No + true + libc.lib + main + + + + + Level3 + MaxSpeed + true + true + false + + + true + true + No + true + libc.lib + main + + + + + + + + + \ No newline at end of file diff --git a/agent/installer/ns_json/Contrib/nsJSON/ConsoleApp/ConsoleApp.vcxproj.filters b/agent/installer/ns_json/Contrib/nsJSON/ConsoleApp/ConsoleApp.vcxproj.filters new file mode 100644 index 00000000000..591001a9386 --- /dev/null +++ b/agent/installer/ns_json/Contrib/nsJSON/ConsoleApp/ConsoleApp.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/agent/installer/ns_json/Contrib/nsJSON/ConsoleApp/main.c b/agent/installer/ns_json/Contrib/nsJSON/ConsoleApp/main.c new file mode 100644 index 00000000000..b8607e850dc --- /dev/null +++ b/agent/installer/ns_json/Contrib/nsJSON/ConsoleApp/main.c @@ -0,0 +1,30 @@ +#include + +int main() +{ + CHAR szInBuffer[32], szOutBuffer[128]; + HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE), hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); + DWORD dwBytesRead, dwBytesWritten; + int i, cchOutBuffer; + + if (ReadFile(hStdIn, szInBuffer, sizeof(szInBuffer), &dwBytesRead, NULL) && dwBytesRead) + { + for (i = lstrlenA(szInBuffer) - 1; i >= 0 && (szInBuffer[i] == '\n' || szInBuffer[i] == '\r' || szInBuffer[i] == '\t' || szInBuffer[i] == ' '); i--) + szInBuffer[i] = '\0'; + + // Pretend to do some work. + Sleep(5000); + + // Return JSON. + //cchOutBuffer = wsprintfA(szOutBuffer, "{\"Input\": \"%s\", \"Output\": \"blah!\"}", szInBuffer); + + // Or return a string. + lstrcpyA(szOutBuffer, "blah!!!!"); + cchOutBuffer = lstrlenA(szOutBuffer); + + WriteFile(hStdOut, szOutBuffer, cchOutBuffer, &dwBytesWritten, NULL); + } + + ExitProcess(0); + return 0; +} \ No newline at end of file diff --git a/agent/installer/ns_json/Contrib/nsJSON/ConsoleAppDotNet/App.config b/agent/installer/ns_json/Contrib/nsJSON/ConsoleAppDotNet/App.config new file mode 100644 index 00000000000..d740e88600a --- /dev/null +++ b/agent/installer/ns_json/Contrib/nsJSON/ConsoleAppDotNet/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/agent/installer/ns_json/Contrib/nsJSON/ConsoleAppDotNet/ConsoleAppDotNet.csproj b/agent/installer/ns_json/Contrib/nsJSON/ConsoleAppDotNet/ConsoleAppDotNet.csproj new file mode 100644 index 00000000000..4bfc5580c12 --- /dev/null +++ b/agent/installer/ns_json/Contrib/nsJSON/ConsoleAppDotNet/ConsoleAppDotNet.csproj @@ -0,0 +1,55 @@ + + + + + Debug + AnyCPU + {DBAA5865-5EF1-4A17-BC19-B68D5E5C13F8} + Exe + Properties + ConsoleAppDotNet + ConsoleAppDotNet + v4.5.2 + 512 + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/agent/installer/ns_json/Contrib/nsJSON/ConsoleAppDotNet/Program.cs b/agent/installer/ns_json/Contrib/nsJSON/ConsoleAppDotNet/Program.cs new file mode 100644 index 00000000000..86fbd3f2a7c --- /dev/null +++ b/agent/installer/ns_json/Contrib/nsJSON/ConsoleAppDotNet/Program.cs @@ -0,0 +1,25 @@ +using System; +using System.Threading; + +namespace ConsoleAppDotNet +{ + class Program + { + static void Main() + { + string input = Console.ReadLine(); + if (input == null) + return; + + input = input.Trim(); + if (input == string.Empty) + return; + + // Pretend to do some work. + Thread.Sleep(TimeSpan.FromSeconds(5)); + + // Return JSON. + Console.Write("{{\"Input\": \"{0}\", \"Output\":\"blah!\"}}", input); + } + } +} diff --git a/agent/installer/ns_json/Contrib/nsJSON/ConsoleAppDotNet/Properties/AssemblyInfo.cs b/agent/installer/ns_json/Contrib/nsJSON/ConsoleAppDotNet/Properties/AssemblyInfo.cs new file mode 100644 index 00000000000..e0174d6b34a --- /dev/null +++ b/agent/installer/ns_json/Contrib/nsJSON/ConsoleAppDotNet/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ConsoleAppDotNet")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ConsoleAppDotNet")] +[assembly: AssemblyCopyright("Copyright © Stuart Welch 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("dbaa5865-5ef1-4a17-bc19-b68d5e5c13f8")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/agent/installer/ns_json/Contrib/nsJSON/ConsoleAppDotNet/obj/Debug/.NETFramework,Version=v4.5.2.AssemblyAttributes.cs b/agent/installer/ns_json/Contrib/nsJSON/ConsoleAppDotNet/obj/Debug/.NETFramework,Version=v4.5.2.AssemblyAttributes.cs new file mode 100644 index 00000000000..78473c060ca --- /dev/null +++ b/agent/installer/ns_json/Contrib/nsJSON/ConsoleAppDotNet/obj/Debug/.NETFramework,Version=v4.5.2.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.5.2", FrameworkDisplayName = "")] diff --git a/agent/installer/ns_json/Contrib/nsJSON/ConsoleAppDotNet/obj/Debug/ConsoleAppDotNet.csproj.AssemblyReference.cache b/agent/installer/ns_json/Contrib/nsJSON/ConsoleAppDotNet/obj/Debug/ConsoleAppDotNet.csproj.AssemblyReference.cache new file mode 100644 index 00000000000..799bd42c846 Binary files /dev/null and b/agent/installer/ns_json/Contrib/nsJSON/ConsoleAppDotNet/obj/Debug/ConsoleAppDotNet.csproj.AssemblyReference.cache differ diff --git a/agent/installer/ns_json/Contrib/nsJSON/ConsoleAppDotNet/obj/Release/.NETFramework,Version=v4.5.2.AssemblyAttributes.cs b/agent/installer/ns_json/Contrib/nsJSON/ConsoleAppDotNet/obj/Release/.NETFramework,Version=v4.5.2.AssemblyAttributes.cs new file mode 100644 index 00000000000..78473c060ca --- /dev/null +++ b/agent/installer/ns_json/Contrib/nsJSON/ConsoleAppDotNet/obj/Release/.NETFramework,Version=v4.5.2.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.5.2", FrameworkDisplayName = "")] diff --git a/agent/installer/ns_json/Contrib/nsJSON/ConsoleAppDotNet/obj/Release/ConsoleAppDotNet.csproj.AssemblyReference.cache b/agent/installer/ns_json/Contrib/nsJSON/ConsoleAppDotNet/obj/Release/ConsoleAppDotNet.csproj.AssemblyReference.cache new file mode 100644 index 00000000000..b3bfe1d05cc Binary files /dev/null and b/agent/installer/ns_json/Contrib/nsJSON/ConsoleAppDotNet/obj/Release/ConsoleAppDotNet.csproj.AssemblyReference.cache differ diff --git a/agent/installer/ns_json/Contrib/nsJSON/JSON.c b/agent/installer/ns_json/Contrib/nsJSON/JSON.c new file mode 100644 index 00000000000..fb4d346e2db --- /dev/null +++ b/agent/installer/ns_json/Contrib/nsJSON/JSON.c @@ -0,0 +1,1538 @@ +/* + JSON parser & writer by Stuart Welch + v1.1.1.0 - 21st November 2017 +*/ + +#include +#include "JSON.h" +#include "pluginapi.h" + +#define IsWhitespace(c) c == TEXT(' ') || c == TEXT('\t') || c == TEXT('\r') || c == TEXT('\n') +#define ntohs(n) (((((unsigned short)(n) & 0xFF)) << 8) | (((unsigned short)(n) & 0xFF00) >> 8)) +static TCHAR hex[] = TEXT("0123456789abcdef"); + +struct JSON_NODE* JSON_Create() +{ + return (struct JSON_NODE*)GlobalAlloc(GPTR, sizeof(struct JSON_NODE)); +} + +PTCHAR JSON_GetQuotedValue(struct JSON_NODE* pNode, const PTCHAR pszDefaultValue) +{ + return pNode && pNode->eType == JNT_QUOTED_VALUE ? pNode->pszValue : pszDefaultValue; +} + +BOOL JSON_IsTrue(struct JSON_NODE* pNode) +{ + if (!pNode || !pNode->pszValue || lstrcmp(pNode->pszValue, TEXT("0")) == 0 || lstrcmpi(pNode->pszValue, TEXT("false")) == 0) + return FALSE; + return TRUE; +} + +static void EatWhitespace(PTCHAR pszBuffer, int* piPos) +{ + while (IsWhitespace(pszBuffer[*piPos])) + (*piPos)++; +} + +static PTCHAR MakeCopy(PTCHAR pszCopyFrom, int iStart, int iEnd) +{ + PTCHAR pszCopy = (PTCHAR)GlobalAlloc(GPTR, sizeof(TCHAR) * (iEnd - iStart + 2)); + if (pszCopy) + { + int i = 0; + for (i = 0; iStart <= iEnd; i++, iStart++) + pszCopy[i] = pszCopyFrom[iStart]; + } + + return pszCopy; +} + +static BOOL IsChar(PTCHAR pszBuffer, int* piPos, TCHAR chExpected) +{ + EatWhitespace(pszBuffer, piPos); + + if (pszBuffer[*piPos] != chExpected) + return FALSE; + + return TRUE; +} + +/*static BOOL IsNumeric(PTCHAR pszBuffer) +{ + int cch = lstrlen(pszBuffer), i; + if (cch == 0) + return FALSE; + + if (pszBuffer[0] == TEXT('0')) + { + if (cch == 1) + return TRUE; + return FALSE; + } + + for (i = 0; i < cch; i++) + if (pszBuffer[i] < TEXT('0') || pszBuffer[i] > TEXT('9')) + return FALSE; + + return TRUE; +}*/ + +static BOOL EatChar(PTCHAR pszBuffer, int* piPos, TCHAR chExpected) +{ + if (!IsChar(pszBuffer, piPos, chExpected)) + return FALSE; + + (*piPos)++; + return TRUE; +} + +static BOOL IsEscaped(PTCHAR pszBuffer, int iPos) +{ + return iPos > 0 && pszBuffer[iPos - 1] == TEXT('\\') && !IsEscaped(pszBuffer, iPos - 1); +} + +static enum JSON_WORD_TYPE EatWord(PTCHAR pszBuffer, int* piPos, PTCHAR* ppszWord) +{ + int iStart, iEnd; + + EatWhitespace(pszBuffer, piPos); + + iStart = *piPos; + iEnd = 0; + *ppszWord = NULL; + + if (pszBuffer[*piPos] == TEXT('"')) + { + iStart++; + + while (TRUE) + { + (*piPos)++; + if (pszBuffer[*piPos] == TEXT('"') && !IsEscaped(pszBuffer, *piPos) || pszBuffer[*piPos] == 0) + { + iEnd = *piPos - 1; + if (pszBuffer[*piPos] == TEXT('"')) + (*piPos)++; + break; + } + } + + *ppszWord = MakeCopy(pszBuffer, iStart, iEnd); + return JWT_STRING; + } + + while (TRUE) + { + if (pszBuffer[*piPos] == TEXT(':') || pszBuffer[*piPos] == TEXT(',') || pszBuffer[*piPos] == TEXT('}') || pszBuffer[*piPos] == TEXT(']') || IsWhitespace(pszBuffer[*piPos]) || pszBuffer[*piPos] == 0) + { + iEnd = *piPos - 1; + break; + } + (*piPos)++; + } + + if (iStart <= iEnd) + { + *ppszWord = MakeCopy(pszBuffer, iStart, iEnd); + return JWT_OTHER; + } + + return JWT_NONE; +} + +static struct JSON_NODE* EatNode(PTCHAR pszBuffer, int* piPos, BOOL bIsValue); + +static struct JSON_NODE* EatNodeArray(PTCHAR pszBuffer, int* piPos) +{ + struct JSON_NODE* pNode = EatNode(pszBuffer, piPos, TRUE); + if (pNode && EatChar(pszBuffer, piPos, TEXT(','))) + pNode->pNext = EatNodeArray(pszBuffer, piPos); + return pNode; +} + +static struct JSON_NODE* EatNode(PTCHAR pszBuffer, int* piPos, BOOL bIsValue) +{ + struct JSON_NODE* pNode = JSON_Create(); + + if (pNode) + { + if (EatChar(pszBuffer, piPos, TEXT('{'))) + { + pNode->eType = JNT_NODE; + pNode->pValue = EatNode(pszBuffer, piPos, FALSE); + if (!pNode->pValue || !EatChar(pszBuffer, piPos, TEXT('}'))) + { + JSON_Delete(&pNode, NULL); + return NULL; + } + } + else if (EatChar(pszBuffer, piPos, TEXT('['))) + { + pNode->eType = JNT_ARRAY; + pNode->pValue = EatNodeArray(pszBuffer, piPos); + if (!pNode->pValue || !EatChar(pszBuffer, piPos, TEXT(']'))) + { + JSON_Delete(&pNode, NULL); + return NULL; + } + } + else + { + PTCHAR pszValue = NULL; + enum JSON_WORD_TYPE eType = EatWord(pszBuffer, piPos, &pszValue); + + if (pszValue) + { + switch (eType) + { + case JWT_STRING: + pNode->eType = JNT_QUOTED_VALUE; + break; + case JWT_OTHER: + pNode->eType = JNT_VALUE; + break; + } + + if (eType != JWT_NONE) + { + // Node is just a value. + if (bIsValue) + { + pNode->pszValue = pszValue; + } + // Node is a key: value pair. + else if (EatChar(pszBuffer, piPos, TEXT(':'))) + { + struct JSON_NODE* pChildNode = EatNode(pszBuffer, piPos, TRUE); + if (!pChildNode) + { + GlobalFree(pNode); + return NULL; + } + + pNode->eType = pChildNode->eType; + pNode->pNext = pChildNode->pNext; + pNode->pValue = pChildNode->pValue; + GlobalFree(pChildNode); + + pNode->pszKey = pszValue; + } + // No key was given; use an empty string. + else + { + pNode->pszKey = (PTCHAR)GlobalAlloc(GPTR, sizeof(TCHAR)); + pNode->pszValue = pszValue; + } + } + } + else + { + GlobalFree(pNode); + return NULL; + } + } + + // Commas are allowed; eat next node. + if (!bIsValue && EatChar(pszBuffer, piPos, TEXT(','))) + { + pNode->pNext = EatNode(pszBuffer, piPos, FALSE); + if (pNode->pNext == NULL) + { + GlobalFree(pNode); + return NULL; + } + } + } + + return pNode; +} + +static struct JSON_NODE* EatRoot(PTCHAR pszBuffer) +{ + int iPos = 0; + return EatNode(pszBuffer, &iPos, FALSE); +} + +static PTCHAR EscapeQuotes(PTCHAR pszStr) +{ + int nQuotes = 0, i, cchLen = lstrlen(pszStr); + PTCHAR pszStrNew; + + for (i = 0; i < cchLen; i++) + if (pszStr[i] == TEXT('"')) + nQuotes++; + + pszStrNew = (PTCHAR)GlobalAlloc(GPTR, sizeof(TCHAR) * (cchLen + nQuotes + 1)); + if (pszStrNew) + { + int j; + + for (i = 0, j = 0; i < cchLen; i++, j++) + { + if (pszStr[i] == TEXT('"') && !IsEscaped(pszStr, i)) + { + pszStrNew[j] = TEXT('\\'); + j++; + } + + pszStrNew[j] = pszStr[i]; + } + } + + return pszStrNew; +} + +void JSON_Delete(struct JSON_NODE** ppNode, struct JSON_NODE* pPrev) +{ + if (ppNode && *ppNode) + { + struct JSON_NODE* pNext = *ppNode; + + if (pPrev) + { + if (pPrev->pNext == *ppNode) + pPrev->pNext = (*ppNode)->pNext; + + if ((pPrev->eType == JNT_NODE || pPrev->eType == JNT_ARRAY) && pPrev->pValue == *ppNode) + pPrev->pValue = (*ppNode)->pNext; + } + + while (pNext) + { + struct JSON_NODE* pNextNext = pNext->pNext; + + if (pNext->pszKey) + GlobalFree(pNext->pszKey); + + switch (pNext->eType) + { + case JNT_NODE: + case JNT_ARRAY: + + if (pNext->pValue) + JSON_Delete(&pNext->pValue, NULL); + + break; + case JNT_VALUE: + case JNT_QUOTED_VALUE: + + GlobalFree(pNext->pszValue); + + break; + } + + GlobalFree(pNext); + + if (pNext == *ppNode) + *ppNode = NULL; + + pNext = pNextNext; + } + } +} + +static PCHAR HandleUTF8Input(PBYTE pbBuffer, int* pcbBuffer) +{ + if (pbBuffer[0] == 0xEF && pbBuffer[1] == 0xBB && pbBuffer[2] == 0xBF) // UTF-8 sig + { + if (pcbBuffer) + *pcbBuffer -= 3; + return (PCHAR)(pbBuffer + 3); + } + + return (PCHAR)pbBuffer; +} + +static PWCHAR HandleUTF16Input(PBYTE pbBuffer, int* pcchBuffer) +{ + if (pbBuffer[0] == 0xFE && pbBuffer[1] == 0xFF) // UTF-16BE BOM + { + int i; + PWCHAR pwszBuffer = (PWCHAR)(pbBuffer + 2); + for (i = 0; pwszBuffer[i] != L'\0'; i++) + pwszBuffer[i] = ntohs(pwszBuffer[i]); + if (pcchBuffer) + *pcchBuffer -= 2; + return pwszBuffer; + } + + if (pbBuffer[0] == 0xFF && pbBuffer[1] == 0xFE && (pbBuffer[2] != 0x00 || pbBuffer[3] != 0x00)) // UTF-16LE BOM + { + if (pcchBuffer) + *pcchBuffer -= 2; + return (PWCHAR)(pbBuffer + 2); + } + + return (PWCHAR)pbBuffer; +} + +static struct JSON_NODE* Parse(PBYTE pbSource, enum JSON_SET_FLAGS eFlags) +{ + struct JSON_NODE* pNode = NULL; + PBYTE pbBuffer = NULL; + DWORD dwSize = 0; + + if (eFlags & JSF_IS_FILE) + { + HANDLE hFile = CreateFile((PTCHAR)pbSource, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + dwSize = GetFileSize(hFile, NULL); + if (dwSize > 0) + { + pbBuffer = (PBYTE)GlobalAlloc(GPTR, dwSize + ((eFlags & JSF_IS_UNICODE) ? sizeof(WCHAR) : sizeof(CHAR))); + if (pbBuffer) + ReadFile(hFile, pbBuffer, dwSize, &dwSize, NULL); + } + CloseHandle(hFile); + } + } + else + { + pbBuffer = pbSource; + dwSize = (eFlags & JSF_IS_UNICODE) ? lstrlenW((PWCHAR)pbSource) : lstrlenA((PCHAR)pbSource); + } + + if (pbBuffer) + { +#ifdef UNICODE + if (eFlags & JSF_IS_UNICODE) + { + pNode = EatRoot(HandleUTF16Input(pbBuffer, NULL)); + } + else + { + int cbBuffer = dwSize; + PWCHAR pwszBuffer = JSON_ToUnicode(HandleUTF8Input(pbBuffer, &cbBuffer), &cbBuffer); + if (pwszBuffer) + { + pNode = EatRoot(pwszBuffer); + GlobalFree(pwszBuffer); + } + } +#else + if (eFlags & JSF_IS_UNICODE) + { + int cchBuffer = dwSize / sizeof(WCHAR); + PCHAR pszBuffer = JSON_FromUnicode(HandleUTF16Input(pbBuffer, &cchBuffer), &cchBuffer, CP_ACP); + if (pszBuffer) + { + pNode = EatRoot(pszBuffer); + GlobalFree(pszBuffer); + } + } + else + { + pNode = EatRoot(HandleUTF8Input(pbBuffer, NULL)); + } +#endif + + if (eFlags & JSF_IS_FILE) + GlobalFree(pbBuffer); + } + + return pNode; +} + +int JSON_Count(struct JSON_NODE* pNode) +{ + int i = 0; + + if (pNode) + { + pNode = pNode->pValue; + for (; pNode != NULL; i++) + pNode = pNode->pNext; + } + + return i; +} + +struct JSON_NODE* JSON_Get(struct JSON_NODE* pNode, PTCHAR pszKey, BOOL bKeyIsIndex) +{ + return JSON_Next(&pNode, pszKey, bKeyIsIndex, FALSE, NULL); +} + +struct JSON_NODE* JSON_GetEx(struct JSON_NODE* pNode, PTCHAR pszKey, BOOL bKeyIsIndex, BOOL bCreate, BOOL* pbCreated) +{ + return JSON_Next(&pNode, pszKey, bKeyIsIndex, bCreate, pbCreated); +} + +struct JSON_NODE* JSON_Next(struct JSON_NODE** ppNode, PTCHAR pszKey, BOOL bKeyIsIndex, BOOL bCreate, BOOL* pbCreated) +{ + if (pbCreated) + *pbCreated = FALSE; + + if (ppNode) + { + struct JSON_NODE* pParent = *ppNode; + struct JSON_NODE* pNext = NULL; + + pszKey = EscapeQuotes(pszKey); + if (pszKey) + { + // We can only get a child node if the parent is also a node or array. + if (pParent->eType == JNT_NODE || pParent->eType == JNT_ARRAY) + { + pNext = pParent->pValue; + + // Get the child node by index. + if (bKeyIsIndex) + { + int i, j = myatoi(pszKey); + + // Negative index? + if (j < 0) + j = JSON_Count(pParent) + j; + + for (i = 0; i < j && pNext != NULL; i++) + { + *ppNode = pNext; + pNext = pNext->pNext; + } + } + // Get the child node by key. + else if (pParent->eType == JNT_NODE) + { + while (pNext != NULL && !(!pNext->pszKey && !*pszKey || lstrcmp(pNext->pszKey, pszKey) == 0)) + { + *ppNode = pNext; + pNext = pNext->pNext; + } + } + // Seek to the end of the array if we're going to add a new node element. + else if (bCreate) + { + while (pNext != NULL) + { + *ppNode = pNext; + pNext = pNext->pNext; + } + } + // Otherwise find an array element that matches. + else + { + while (pNext != NULL) + { + if ((pNext->eType == JNT_VALUE || pNext->eType == JNT_QUOTED_VALUE) && lstrcmp(pNext->pszValue, pszKey) == 0) + break; + + *ppNode = pNext; + pNext = pNext->pNext; + } + } + + // No existing child node found and the caller wants to create one. + if (!pNext && bCreate) + { + struct JSON_NODE* pNew = (struct JSON_NODE*)GlobalAlloc(GPTR, sizeof(struct JSON_NODE)); + pNew->eType = JNT_NODE; + + if (pbCreated) + *pbCreated = TRUE; + + // Adding a new node to an array. + if (pParent->eType == JNT_ARRAY && !bKeyIsIndex) + { + pNew->pValue = (struct JSON_NODE*)GlobalAlloc(GPTR, sizeof(struct JSON_NODE)); + pNew->pValue->eType = JNT_NODE; + + if (*pszKey) + { + pNew->pValue->pszKey = (PTCHAR)GlobalAlloc(GPTR, sizeof(TCHAR) * (lstrlen(pszKey) + 1)); + if (pNew->pValue->pszKey) + lstrcpy(pNew->pValue->pszKey, pszKey); + } + + if (*ppNode != pParent) + (*ppNode)->pNext = pNew; + else + pParent->pValue = pNew; + + pNext = pNew->pValue; + } + // Change parent to an array. + else if (pParent->eType == JNT_NODE && bKeyIsIndex) + { + pParent->eType = JNT_ARRAY; + + if (*ppNode != pParent) + (*ppNode)->pNext = pNew; + else + pParent->pValue = pNew; + + pNext = pNew; + } + // Adding a new node to a node. + else + { + if (!bKeyIsIndex) + { + if (*pszKey) + { + pNew->pszKey = (PTCHAR)GlobalAlloc(GPTR, sizeof(TCHAR) * (lstrlen(pszKey) + 1)); + if (pNew->pszKey) + lstrcpy(pNew->pszKey, pszKey); + } + else + { + pNew->pszKey = (PTCHAR)GlobalAlloc(GPTR, sizeof(TCHAR)); + } + } + + if (*ppNode != pParent) + (*ppNode)->pNext = pNew; + else + pParent->pValue = pNew; + + pNext = pNew; + } + } + } + + GlobalFree(pszKey); + } + + return pNext; + } + + return NULL; +} + +BOOL JSON_Set(struct JSON_NODE* pNode, PBYTE pbValue, enum JSON_SET_FLAGS eFlags) +{ + if (pNode) + { + if (eFlags & JSF_IS_RAW) + { + // We are overwriting the node's value. + switch (pNode->eType) + { + case JNT_NODE: + case JNT_ARRAY: + + if (pNode->pValue) + JSON_Delete(&pNode->pValue, NULL); + + break; + case JNT_VALUE: + case JNT_QUOTED_VALUE: + + if (pNode->pszValue) + GlobalFree(pNode->pszValue); + + break; + } + + pNode->eType = JNT_QUOTED_VALUE; + +#ifdef UNICODE + if (eFlags & JSF_IS_UNICODE) + { + pNode->pszValue = JSON_Escape((PWCHAR)pbValue, JEF_NONE); + } + else + { + int cchValue = lstrlenA((PCHAR)pbValue); + PWCHAR pwszConverted = JSON_ToUnicode((PCHAR)pbValue, &cchValue); + if (pwszConverted) + { + pNode->pszValue = JSON_Escape(pwszConverted, JEF_NONE); + GlobalFree(pwszConverted); + } + else + { + pNode->pszValue = NULL; + } + } +#else + if (eFlags & JSF_IS_UNICODE) + { + int cchValue = lstrlenW((PWCHAR)pbValue); + PCHAR pszConverted = JSON_FromUnicode((PWCHAR)pbValue, &cchValue, CP_ACP); + if (pszConverted) + { + pNode->pszValue = JSON_Escape(pszConverted, JEF_NONE); + GlobalFree(pszConverted); + } + else + { + pNode->pszValue = NULL; + } + } + else + { + pNode->pszValue = JSON_Escape((PCHAR)pbValue, JEF_NONE); + } +#endif + } + else + { + struct JSON_NODE* pChildNode = Parse(pbValue, eFlags); + if (!pChildNode) + return FALSE; + + switch (pNode->eType) + { + case JNT_NODE: + + // We are overwriting the node's value. + if (pNode->pValue) + JSON_Delete(&pNode->pValue, NULL); + + switch (pChildNode->eType) + { + case JNT_NODE: + case JNT_ARRAY: + + // Child node is a key: value pair; set it as the parent node's value. + if (pChildNode->pszKey) + { + pNode->eType = JNT_NODE; + pNode->pValue = pChildNode; + } + // Child node is a node without a key; overwrite the parent node's value with the child node's value. + else + { + pNode->eType = pChildNode->eType; + pNode->pValue = pChildNode->pValue; + GlobalFree(pChildNode); + } + + break; + default: + + // Replace the node's value. + pNode->eType = pChildNode->eType; + pNode->pszValue = pChildNode->pszValue; + GlobalFree(pChildNode); + + break; + } + + break; + case JNT_ARRAY: + + if (pNode->pValue) + { + struct JSON_NODE* pArrayNode = pNode->pValue; + + // Seek to the end of the array and then append to the end. + while (TRUE) + { + if (pArrayNode->pNext == NULL) + break; + + pArrayNode = pArrayNode->pNext; + } + + pArrayNode->pNext = pChildNode; + } + // Replacing node. + else + { + pNode->eType = pChildNode->eType; + pNode->pValue = pChildNode->pValue; + GlobalFree(pChildNode); + } + + break; + case JNT_VALUE: + case JNT_QUOTED_VALUE: + + // We are overwriting the node's value. + if (pNode->pszValue) + GlobalFree(pNode->pszValue); + + switch (pChildNode->eType) + { + case JNT_NODE: + case JNT_ARRAY: + + // Child node is a key: value pair; set it as the parent node's value. + if (pChildNode->pszKey) + { + pNode->eType = pChildNode->eType; + pNode->pValue = pChildNode; + } + // Child node is a node without a key; overwrite the parent node's value with the child node's value. + else + { + pNode->eType = pChildNode->eType; + pNode->pValue = pChildNode->pValue; + GlobalFree(pChildNode); + } + + break; + default: + + // Replace the node's value. + pNode->eType = pChildNode->eType; + pNode->pszValue = pChildNode->pszValue; + GlobalFree(pChildNode); + + break; + } + + break; + } + } + } + + return TRUE; +} + +BOOL JSON_SetEx(struct JSON_NODE* pNode, PTCHAR pszKey, BOOL bKeyIsIndex, PBYTE pbValue, enum JSON_SET_FLAGS eFlags) +{ + struct JSON_NODE* pNew = JSON_Next(&pNode, pszKey, bKeyIsIndex, TRUE, NULL); + if (pNew) + return JSON_Set(pNew, pbValue, eFlags); + return FALSE; +} + +static void MyWriteFile(HANDLE hFile, PTCHAR pszText, int cchText, BOOL bAsUnicode) +{ + DWORD dwBytes; + +#ifdef UNICODE + if (bAsUnicode) + { + WriteFile(hFile, pszText, sizeof(WCHAR) * cchText, &dwBytes, NULL); + } + else + { + PCHAR pszConverted = JSON_FromUnicode(pszText, &cchText, CP_ACP); + if (pszConverted) + { + WriteFile(hFile, pszConverted, cchText, &dwBytes, NULL); + GlobalFree(pszConverted); + } + } +#else + if (bAsUnicode) + { + PWCHAR pwszConverted = JSON_ToUnicode(pszText, &cchText); + if (pwszConverted) + { + WriteFile(hFile, pwszConverted, cchText, &dwBytes, NULL); + GlobalFree(pwszConverted); + } + } + else + { + WriteFile(hFile, pszText, cchText, &dwBytes, NULL); + } +#endif +} + +static void MyWriteFileEx(HANDLE hFile, PTCHAR pszText, int cchText, BOOL bAsUnicode, int iRepeat) +{ + int i = 0; + + for (; i < iRepeat; i++) + { + MyWriteFile(hFile, pszText, cchText, bAsUnicode); + } +} + +static void SerializeToFile(HANDLE hFile, struct JSON_NODE* pNode, int iIndent, BOOL bAsUnicode) +{ + if (!pNode) + return; + + if (pNode->pszKey) + { + MyWriteFile(hFile, TEXT("\""), 1, bAsUnicode); + MyWriteFile(hFile, pNode->pszKey, lstrlen(pNode->pszKey), bAsUnicode); + MyWriteFile(hFile, TEXT("\":"), 2, bAsUnicode); + + if (iIndent) + { + MyWriteFile(hFile, TEXT(" "), 1, bAsUnicode); + } + } + + switch (pNode->eType) + { + case JNT_NODE: + case JNT_ARRAY: + + MyWriteFile(hFile, pNode->eType == JNT_ARRAY ? TEXT("[") : TEXT("{"), 1, bAsUnicode); + + if (iIndent) + { + MyWriteFile(hFile, TEXT("\r\n"), 2, bAsUnicode); + MyWriteFileEx(hFile, TEXT(JSON_INDENT_CHAR), 1, bAsUnicode, iIndent); + } + + SerializeToFile(hFile, pNode->pValue, iIndent ? iIndent + JSON_INDENT : 0, bAsUnicode); + + if (iIndent) + { + MyWriteFile(hFile, TEXT("\r\n"), 2, bAsUnicode); + MyWriteFileEx(hFile, TEXT(JSON_INDENT_CHAR), 1, bAsUnicode, iIndent - 1); + } + + MyWriteFile(hFile, pNode->eType == JNT_ARRAY ? TEXT("]") : TEXT("}"), 1, bAsUnicode); + + break; + case JNT_VALUE: + + MyWriteFile(hFile, pNode->pszValue, lstrlen(pNode->pszValue), bAsUnicode); + + break; + case JNT_QUOTED_VALUE: + + MyWriteFile(hFile, TEXT("\""), 1, bAsUnicode); + MyWriteFile(hFile, pNode->pszValue, lstrlen(pNode->pszValue), bAsUnicode); + MyWriteFile(hFile, TEXT("\""), 1, bAsUnicode); + + break; + } + + if (pNode->pNext) + { + pNode = pNode->pNext; + + MyWriteFile(hFile, TEXT(","), 1, bAsUnicode); + + if (iIndent) + { + MyWriteFile(hFile, TEXT("\r\n"), 2, bAsUnicode); + MyWriteFileEx(hFile, TEXT(JSON_INDENT_CHAR), 1, bAsUnicode, iIndent - 1); + } + + SerializeToFile(hFile, pNode, iIndent, bAsUnicode); + } +} + +static void MyStrCpy(PTCHAR* ppszBuffer, int* pcchBuffer, int* piPos, PTCHAR pszCopy, int cchCopyLen, BOOL bResize, DWORD* pdwLastError) +{ + if (*piPos + cchCopyLen <= *pcchBuffer) + { + if (ppszBuffer && *ppszBuffer) + lstrcpy(*ppszBuffer + *piPos, pszCopy); + *piPos += cchCopyLen; + } + else if (bResize) + { + *pcchBuffer *= 2; + + if (ppszBuffer && *ppszBuffer) + { + PTCHAR pszNewBuffer = (PTCHAR)GlobalReAlloc(*ppszBuffer, *pcchBuffer, GMEM_ZEROINIT | GMEM_MOVEABLE); + if (!pszNewBuffer) + { + *pdwLastError = GetLastError(); + GlobalFree(*ppszBuffer); + *ppszBuffer = NULL; + } + else + { + *ppszBuffer = pszNewBuffer; + } + } + + MyStrCpy(ppszBuffer, pcchBuffer, piPos, pszCopy, cchCopyLen, TRUE, pdwLastError); + } + else + { + int i = 0; + for (; i < cchCopyLen && *piPos < *pcchBuffer; i++, (*piPos)++) + { + if (ppszBuffer && *ppszBuffer) + (*ppszBuffer)[*piPos] = pszCopy[i]; + } + } +} + +static void MyStrCpyEx(PTCHAR* ppszBuffer, int* pcchBuffer, int* piPos, PTCHAR pszCopy, int cchCopyLen, int iRepeat, BOOL bResize, DWORD* pdwLastError) +{ + int i = 0; + for (; i < iRepeat; i++) + { + MyStrCpy(ppszBuffer, pcchBuffer, piPos, pszCopy, cchCopyLen, bResize, pdwLastError); + } +} + +static void SerializeToBuffer(PTCHAR* ppszBuffer, int* pcchBuffer, struct JSON_NODE* pNode, int* piPos, int iIndent, BOOL bResize, DWORD* pdwLastError) +{ + if (!pNode) + { + if (ppszBuffer && *ppszBuffer) + lstrcpy(*ppszBuffer + *piPos, TEXT("")); + return; + } + + if (pNode->pszKey) + { + MyStrCpy(ppszBuffer, pcchBuffer, piPos, TEXT("\""), 1, bResize, pdwLastError); + MyStrCpy(ppszBuffer, pcchBuffer, piPos, pNode->pszKey, lstrlen(pNode->pszKey), bResize, pdwLastError); + MyStrCpy(ppszBuffer, pcchBuffer, piPos, TEXT("\":"), 2, bResize, pdwLastError); + + if (iIndent) + { + MyStrCpy(ppszBuffer, pcchBuffer, piPos, TEXT(" "), 1, bResize, pdwLastError); + } + } + + switch (pNode->eType) + { + case JNT_NODE: + case JNT_ARRAY: + + MyStrCpy(ppszBuffer, pcchBuffer, piPos, pNode->eType == JNT_ARRAY ? TEXT("[") : TEXT("{"), 1, bResize, pdwLastError); + + if (iIndent) + { + MyStrCpy(ppszBuffer, pcchBuffer, piPos, TEXT("\r\n"), 2, bResize, pdwLastError); + MyStrCpyEx(ppszBuffer, pcchBuffer, piPos, TEXT(JSON_INDENT_CHAR), 1, iIndent, bResize, pdwLastError); + } + + SerializeToBuffer(ppszBuffer, pcchBuffer, pNode->pValue, piPos, iIndent ? iIndent + JSON_INDENT : 0, bResize, pdwLastError); + + if (iIndent) + { + MyStrCpy(ppszBuffer, pcchBuffer, piPos, TEXT("\r\n"), 2, bResize, pdwLastError); + MyStrCpyEx(ppszBuffer, pcchBuffer, piPos, TEXT(JSON_INDENT_CHAR), 1, iIndent - 1, bResize, pdwLastError); + } + + MyStrCpy(ppszBuffer, pcchBuffer, piPos, pNode->eType == JNT_ARRAY ? TEXT("]") : TEXT("}"), 1, bResize, pdwLastError); + + break; + case JNT_VALUE: + + MyStrCpy(ppszBuffer, pcchBuffer, piPos, pNode->pszValue, lstrlen(pNode->pszValue), bResize, pdwLastError); + + break; + case JNT_QUOTED_VALUE: + + MyStrCpy(ppszBuffer, pcchBuffer, piPos, TEXT("\""), 1, bResize, pdwLastError); + MyStrCpy(ppszBuffer, pcchBuffer, piPos, pNode->pszValue, lstrlen(pNode->pszValue), bResize, pdwLastError); + MyStrCpy(ppszBuffer, pcchBuffer, piPos, TEXT("\""), 1, bResize, pdwLastError); + + break; + } + + if (pNode->pNext) + { + pNode = pNode->pNext; + + MyStrCpy(ppszBuffer, pcchBuffer, piPos, TEXT(","), 1, bResize, pdwLastError); + + if (iIndent) + { + MyStrCpy(ppszBuffer, pcchBuffer, piPos, TEXT("\r\n"), 2, bResize, pdwLastError); + MyStrCpyEx(ppszBuffer, pcchBuffer, piPos, TEXT(JSON_INDENT_CHAR), 1, iIndent - 1, bResize, pdwLastError); + } + + SerializeToBuffer(ppszBuffer, pcchBuffer, pNode, piPos, iIndent, bResize, pdwLastError); + } +} + +static BOOL AddRoot(struct JSON_NODE** ppNode) +{ + struct JSON_NODE* pRoot = JSON_Create(); + if (pRoot) + { + pRoot->eType = JNT_NODE; + pRoot->pValue = *ppNode; + *ppNode = pRoot; + return TRUE; + } + + return FALSE; +} + +static TCHAR i2a(TCHAR code) +{ + return hex[code & 15]; +} + +static int EscapePostData(PTCHAR* ppszPostData, int* pcchPostData, DWORD* pdwLastError) +{ + int cchLength = 0; + if (ppszPostData && *ppszPostData) + { + PTCHAR pszBuffer = (PTCHAR)GlobalAlloc(GPTR, (lstrlen(*ppszPostData) * 3 + 1) * sizeof(TCHAR)); + + if (pszBuffer) + { + PTCHAR pszBufferPtr = pszBuffer, pszPostDataPtr = *ppszPostData; + int iPos = 0; + + while (*pszPostDataPtr) + { + if (IsCharAlphaNumeric(*pszPostDataPtr) || *pszPostDataPtr == TEXT('-') || *pszPostDataPtr == TEXT('_') || *pszPostDataPtr == TEXT('.') || *pszPostDataPtr == TEXT('~')) + { + *pszBufferPtr++ = *pszPostDataPtr; + } + else if (*pszPostDataPtr == TEXT(' ')) + { + *pszBufferPtr++ = TEXT('+'); + } + else + { + *pszBufferPtr++ = TEXT('%'); + *pszBufferPtr++ = i2a(*pszPostDataPtr >> 4); + *pszBufferPtr++ = i2a(*pszPostDataPtr & 15); + } + + pszPostDataPtr++; + } + + if ((cchLength = lstrlen(pszBuffer)) > 0) + MyStrCpy(ppszPostData, pcchPostData, &iPos, pszBuffer, cchLength, TRUE, pdwLastError); + + GlobalFree(pszBuffer); + } + } + + return cchLength; +} + +BOOL JSON_Serialize(struct JSON_NODE* pNode, PTCHAR pszBuffer, int cchBuffer, BOOL bIsFile, BOOL bAsUnicode, BOOL bFormat) +{ + DWORD dwLastError = 0; + + BOOL bAddRoot = pNode && pNode->pszKey && *pNode->pszKey; + if (bAddRoot && !AddRoot(&pNode)) + bAddRoot = FALSE; + + if (bIsFile) + { + HANDLE hFile = CreateFile(pszBuffer, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + SerializeToFile(hFile, pNode, bFormat ? JSON_INDENT : 0, bAsUnicode); + CloseHandle(hFile); + } + else + { + dwLastError = GetLastError(); + } + } + else + { + int iPos = 0; + SerializeToBuffer(&pszBuffer, &cchBuffer, pNode, &iPos, bFormat ? JSON_INDENT : 0, FALSE, &dwLastError); + } + + if (bAddRoot) + GlobalFree(pNode); + + SetLastError(dwLastError); + return dwLastError == 0; +} + +PTCHAR JSON_SerializeAlloc(struct JSON_NODE* pNode, BOOL bFormat, BOOL bAsPostData) +{ + DWORD dwLastError = 0; + int cchBuffer = 2048; + PTCHAR pszBuffer = (PTCHAR)GlobalAlloc(GPTR, cchBuffer * sizeof(TCHAR)); + + if (pszBuffer) + { + BOOL bAddRoot = pNode && pNode->pszKey && *pNode->pszKey; + if (bAddRoot && !AddRoot(&pNode)) + bAddRoot = FALSE; + + if (bAsPostData) + { + struct JSON_NODE* pNext = pNode->pValue; + int iPos = 0; + int cchValueBuffer = 2048; + PTCHAR pszValueBuffer = (PTCHAR)GlobalAlloc(GPTR, cchValueBuffer * sizeof(TCHAR)); + if (pszValueBuffer) + { + while (pNext) + { + switch (pNext->eType) + { + case JNT_ARRAY: + { + struct JSON_NODE* pArrayNext = pNext->pValue; + while (pArrayNext) + { + int iValuePos = 0; + MyStrCpy(&pszBuffer, &cchBuffer, &iPos, pNext->pszKey, lstrlen(pNext->pszKey), TRUE, &dwLastError); + MyStrCpy(&pszBuffer, &cchBuffer, &iPos, TEXT("[]="), 3, TRUE, &dwLastError); + + switch (pArrayNext->eType) + { + case JNT_NODE: + case JNT_ARRAY: + SerializeToBuffer(&pszValueBuffer, &cchValueBuffer, pArrayNext, &iValuePos, 0, TRUE, &dwLastError); + break; + default: + MyStrCpy(&pszValueBuffer, &cchValueBuffer, &iValuePos, pArrayNext->pszValue, lstrlen(pArrayNext->pszValue), TRUE, &dwLastError); + break; + } + + iValuePos = EscapePostData(&pszValueBuffer, &cchValueBuffer, &dwLastError); + if (iValuePos > 0) + MyStrCpy(&pszBuffer, &cchBuffer, &iPos, pszValueBuffer, iValuePos, TRUE, &dwLastError); + + pArrayNext = pArrayNext->pNext; + if (pArrayNext) + MyStrCpy(&pszBuffer, &cchBuffer, &iPos, TEXT("&"), 1, TRUE, &dwLastError); + } + } + break; + + default: + { + int iValuePos = 0; + MyStrCpy(&pszBuffer, &cchBuffer, &iPos, pNext->pszKey, lstrlen(pNext->pszKey), TRUE, &dwLastError); + + if (pNext->eType != JNT_VALUE || pNext->eType == JNT_VALUE && lstrcmpi(pNext->pszValue, TEXT("true")) != 0) + { + MyStrCpy(&pszBuffer, &cchBuffer, &iPos, TEXT("="), 1, TRUE, &dwLastError); + + if (pNext->eType == JNT_NODE) + SerializeToBuffer(&pszValueBuffer, &cchValueBuffer, pNext->pValue, &iValuePos, bFormat ? JSON_INDENT : 0, TRUE, &dwLastError); + else + MyStrCpy(&pszValueBuffer, &cchValueBuffer, &iValuePos, pNext->pszValue, lstrlen(pNext->pszValue), TRUE, &dwLastError); + + iValuePos = EscapePostData(&pszValueBuffer, &cchValueBuffer, &dwLastError); + if (iValuePos > 0) + MyStrCpy(&pszBuffer, &cchBuffer, &iPos, pszValueBuffer, iValuePos, TRUE, &dwLastError); + } + } + break; + } + + pNext = pNext->pNext; + if (pNext) + MyStrCpy(&pszBuffer, &cchBuffer, &iPos, TEXT("&"), 1, TRUE, &dwLastError); + } + + GlobalFree(pszValueBuffer); + } + } + else + { + int iPos = 0; + SerializeToBuffer(&pszBuffer, &cchBuffer, pNode, &iPos, bFormat ? JSON_INDENT : 0, TRUE, &dwLastError); + } + + if (bAddRoot) + GlobalFree(pNode); + } + + SetLastError(dwLastError); + return pszBuffer; +} + +PTCHAR JSON_Expand(struct JSON_NODE* pNode) +{ + PTCHAR pszExpanded = NULL; + int i, j, cch = lstrlen(pNode->pszValue); + TCHAR szUnicode[7]; + + pszExpanded = (PTCHAR)GlobalAlloc(GPTR, sizeof(TCHAR) * (cch + 1)); + if (pszExpanded) + { + for (i = 0, j = 0; i < cch; i++, j++) + { + if (pNode->pszValue[i] == TEXT('\\')) + { + switch (pNode->pszValue[i + 1]) + { + case TEXT('"'): + case TEXT('\\'): + case TEXT('/'): + pszExpanded[j] = pNode->pszValue[i + 1]; + i++; + break; + case TEXT('b'): + pszExpanded[j] = TEXT('\b'); + i++; + break; + case TEXT('f'): + pszExpanded[j] = TEXT('\f'); + i++; + break; + case TEXT('n'): + pszExpanded[j] = TEXT('\n'); + i++; + break; + case TEXT('r'): + pszExpanded[j] = TEXT('\r'); + i++; + break; + case TEXT('t'): + pszExpanded[j] = TEXT('\t'); + i++; + break; + case TEXT('u'): + wsprintf(szUnicode, TEXT("0x%c%c%c%c"), pNode->pszValue[i + 2], pNode->pszValue[i + 3], pNode->pszValue[i + 4], pNode->pszValue[i + 5]); +#ifdef UNICODE + pszExpanded[j] = (WCHAR)myatoi(szUnicode); +#else + wsprintfW((PWCHAR)szUnicode, L"%c", myatoi(szUnicode)); + if (WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, (PWCHAR)szUnicode, 1, NULL, 0, NULL, NULL) == 1) + WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, (PWCHAR)szUnicode, 1, pszExpanded + j, 1, NULL, NULL); + else + lstrcpyA(pszExpanded + j, "?"); +#endif + i += 5; + break; + } + } + else + { + pszExpanded[j] = pNode->pszValue[i]; + } + } + } + + return pszExpanded; +} + +PTCHAR JSON_Escape(PTCHAR pszValue, enum JSON_ESCAPE_FLAGS eFlags) +{ + PTCHAR pszEscaped; + int i, cch = lstrlen(pszValue), cchNew = cch; + BOOL bAlreadyQuoted = cch > 1 && pszValue[0] == TEXT('"') && pszValue[cch - 1] == TEXT('"'); + BOOL bQuote = (eFlags & JEF_QUOTE) && ((eFlags & JEF_ALWAYS_QUOTE) || !bAlreadyQuoted); + if (bQuote) + cchNew += 2; + + for (i = 0; i < cch; i++) + { + switch (pszValue[i]) + { + case TEXT('\b'): + case TEXT('\f'): + case TEXT('\n'): + case TEXT('\r'): + case TEXT('\t'): + case TEXT('\\'): + case TEXT('"'): + cchNew++; + break; + default: + if ((eFlags & JEF_ESCAPE_UNICODE) && (pszValue[i] < 32 || pszValue[i] > 126)) + cchNew += 6; + break; + } + } + + pszEscaped = (PTCHAR)GlobalAlloc(GPTR, sizeof(TCHAR) * (cchNew + 1)); + + if (pszEscaped && cch < cchNew) + { + int j; + + if (bQuote) + { + pszEscaped[0] = TEXT('"'); + i = 0; + j = 1; + } + else if (bAlreadyQuoted) + { + pszEscaped[0] = TEXT('"'); + i = 1; + j = 1; + cch--; + } + else + { + i = 0; + j = 0; + } + + for (; i < cch; i++, j++) + { + switch (pszValue[i]) + { + case TEXT('\b'): + pszEscaped[j++] = TEXT('\\'); + pszEscaped[j] = TEXT('b'); + break; + case TEXT('\f'): + pszEscaped[j++] = TEXT('\\'); + pszEscaped[j] = TEXT('f'); + break; + case TEXT('\n'): + pszEscaped[j++] = TEXT('\\'); + pszEscaped[j] = TEXT('n'); + break; + case TEXT('\r'): + pszEscaped[j++] = TEXT('\\'); + pszEscaped[j] = TEXT('r'); + break; + case TEXT('\t'): + pszEscaped[j++] = TEXT('\\'); + pszEscaped[j] = TEXT('t'); + break; + case TEXT('\\'): + case TEXT('"'): + pszEscaped[j++] = TEXT('\\'); + pszEscaped[j] = pszValue[i]; + break; + default: + if ((eFlags & JEF_ESCAPE_UNICODE) && (pszValue[i] < 32 || pszValue[i] > 126)) + { + j += wsprintf(pszEscaped + j, TEXT("\\u%04x"), (unsigned char)pszValue[i]) - 1; + } + else + { + pszEscaped[j] = pszValue[i]; + } + break; + } + } + + if (bQuote || bAlreadyQuoted) + { + pszEscaped[j] = TEXT('"'); + } + } + else + { + lstrcpy(pszEscaped, pszValue); + } + + return pszEscaped; +} + +PCHAR JSON_FromUnicode(PWCHAR pwszText, int* pcchText, UINT nCodePage) +{ + int cbConverted = WideCharToMultiByte(nCodePage, WC_COMPOSITECHECK, pwszText, *pcchText, NULL, 0, NULL, NULL); + if (cbConverted > 0) + { + PCHAR pszBuffer = (PCHAR)GlobalAlloc(GPTR, sizeof(CHAR) * (cbConverted + 1)); + if (pszBuffer) + { + if (WideCharToMultiByte(nCodePage, WC_COMPOSITECHECK, pwszText, *pcchText, pszBuffer, cbConverted, NULL, NULL) > 0) + { + *pcchText = cbConverted; + return pszBuffer; + } + + GlobalFree(pszBuffer); + } + } + + return NULL; +} + +PWCHAR JSON_ToUnicode(PCHAR pszText, int* pcbText) +{ + int cchConverted = MultiByteToWideChar(CP_ACP, MB_COMPOSITE, pszText, *pcbText, NULL, 0); + if (cchConverted > 0) + { + PWCHAR pwszBuffer = (PWCHAR)GlobalAlloc(GPTR, sizeof(WCHAR) * (cchConverted + 1)); + if (pwszBuffer) + { + if (MultiByteToWideChar(CP_ACP, MB_COMPOSITE, pszText, *pcbText, pwszBuffer, cchConverted) > 0) + { + *pcbText = cchConverted; + return pwszBuffer; + } + + GlobalFree(pwszBuffer); + } + } + + return NULL; +} + +static BOOL _Sort(enum JSON_SORT_FLAGS eFlags, struct JSON_NODE* pCurrent, struct JSON_NODE* pNext) +{ + BOOL bMove = FALSE; + + if (eFlags & JSF_BY_KEYS) + { + if (pNext->eType == JNT_NODE) + { + if (eFlags & JSF_RECURSIVE) + JSON_Sort(pNext, eFlags); + } + + if (eFlags & JSF_NUMERIC) + { + if (myatoi(pCurrent->pszKey) > myatoi(pNext->pszKey)) + bMove = TRUE; + } + else if (eFlags & JSF_CASE_SENSITIVE) + { + if (lstrcmp(pCurrent->pszKey, pNext->pszKey) > 0) + bMove = TRUE; + } + else + { + if (lstrcmpi(pCurrent->pszKey, pNext->pszKey) > 0) + bMove = TRUE; + } + } + else + { + if (pNext->eType == JNT_ARRAY || pNext->eType == JNT_NODE) + { + if (eFlags & JSF_RECURSIVE) + JSON_Sort(pNext, eFlags); + return FALSE; + } + + if (pCurrent->eType == JNT_ARRAY || pCurrent->eType == JNT_NODE) + { + return FALSE; + } + + if (eFlags & JSF_NUMERIC) + { + if (myatoi(pCurrent->pszValue) > myatoi(pNext->pszValue)) + bMove = TRUE; + } + else if (eFlags & JSF_CASE_SENSITIVE) + { + if (lstrcmp(pCurrent->pszValue, pNext->pszValue) > 0) + bMove = TRUE; + } + else + { + if (lstrcmpi(pCurrent->pszValue, pNext->pszValue) > 0) + bMove = TRUE; + } + } + + if (eFlags & JSF_DESCENDING) + bMove = !bMove; + + return bMove; +} + +void JSON_Sort(struct JSON_NODE* pNode, enum JSON_SORT_FLAGS eFlags) +{ + if (pNode->eType != JNT_NODE && pNode->eType != JNT_ARRAY) + return; + + while (TRUE) + { + BOOL bSwapped = FALSE; + struct JSON_NODE** ppLink = &pNode->pValue; + struct JSON_NODE* pCurrent = pNode->pValue; + struct JSON_NODE* pNext; + + while (pNext = pCurrent->pNext) + { + if (_Sort(eFlags, pCurrent, pNext)) + { + pCurrent->pNext = pNext->pNext; + pNext->pNext = pCurrent; + *ppLink = pCurrent = pNext; + bSwapped |= TRUE; + } + + ppLink = &pCurrent->pNext; + pCurrent = pNext; + } + + if (!bSwapped) + break; + } +} \ No newline at end of file diff --git a/agent/installer/ns_json/Contrib/nsJSON/JSON.h b/agent/installer/ns_json/Contrib/nsJSON/JSON.h new file mode 100644 index 00000000000..b050296f857 --- /dev/null +++ b/agent/installer/ns_json/Contrib/nsJSON/JSON.h @@ -0,0 +1,86 @@ +#ifndef __JSON_H__ +#define __JSON_H__ + +#define JSON_INDENT 1 +#define JSON_INDENT_CHAR "\t" + +enum JSON_WORD_TYPE +{ + JWT_STRING, + JWT_OTHER, + JWT_NONE +}; + +enum JSON_NODE_TYPE +{ + // node = key: [node] + JNT_NODE, + // node = key: [ array ] + JNT_ARRAY, + // node = key: value + JNT_VALUE, + // node = key: "value" + JNT_QUOTED_VALUE +}; + +enum JSON_SET_FLAGS +{ + JSF_NONE = 0, + JSF_IS_FILE = 1, + JSF_IS_UNICODE = 2, + JSF_IS_RAW = 4 +}; + +enum JSON_ESCAPE_FLAGS +{ + JEF_NONE = 0, + JEF_ESCAPE_UNICODE = 1, + JEF_QUOTE = 2, + JEF_ALWAYS_QUOTE = 4 +}; + +struct JSON_NODE +{ + enum JSON_NODE_TYPE eType; + struct JSON_NODE* pNext; + PTCHAR pszKey; + union + { + PTCHAR pszValue; + struct JSON_NODE* pValue; + }; +}; + +enum JSON_SORT_FLAGS +{ + // Sort descending instead of ascending. + JSF_DESCENDING = 1, + // Numeric comparison rather than string. + JSF_NUMERIC = 2, + // Sort case sensitive. + JSF_CASE_SENSITIVE = 4, + // Sort by keys rather than by values. + JSF_BY_KEYS = 8, + // Sort recursively. + JSF_RECURSIVE = 16 +}; + +struct JSON_NODE* JSON_Create(); +BOOL JSON_IsTrue(struct JSON_NODE* pNode); +PTCHAR JSON_GetQuotedValue(struct JSON_NODE* pNode, const PTCHAR pszDefaultValue); +void JSON_Delete(struct JSON_NODE** ppNode, struct JSON_NODE* pPrev); +int JSON_Count(struct JSON_NODE* pNode); +struct JSON_NODE* JSON_Get(struct JSON_NODE* pNode, PTCHAR pszKey, BOOL bKeyIsIndex); +struct JSON_NODE* JSON_GetEx(struct JSON_NODE* pNode, PTCHAR pszKey, BOOL bKeyIsIndex, BOOL bCreate, BOOL* pbCreated); +struct JSON_NODE* JSON_Next(struct JSON_NODE** ppNode, PTCHAR pszKey, BOOL bKeyIsIndex, BOOL bCreate, BOOL* pbCreated); +BOOL JSON_Set(struct JSON_NODE* pNode, PBYTE pbValue, enum JSON_SET_FLAGS eFlags); +BOOL JSON_SetEx(struct JSON_NODE* pNode, PTCHAR pszKey, BOOL bKeyIsIndex, PBYTE pbValue, enum JSON_SET_FLAGS eFlags); +BOOL JSON_Serialize(struct JSON_NODE* pNode, PTCHAR pszBuffer, int cchBuffer, BOOL bIsFile, BOOL bAsUnicode, BOOL bFormat); +PTCHAR JSON_SerializeAlloc(struct JSON_NODE* pNode, BOOL bFormat, BOOL bAsPostData); +PTCHAR JSON_Expand(struct JSON_NODE* pNode); +PTCHAR JSON_Escape(PTCHAR pszValue, enum JSON_ESCAPE_FLAGS eFlags); +PCHAR JSON_FromUnicode(PWCHAR pwszText, int* pcchText, UINT nCodePage); +PWCHAR JSON_ToUnicode(PCHAR pszText, int* pcbText); +void JSON_Sort(struct JSON_NODE* pNode, enum JSON_SORT_FLAGS eFlags); + +#endif \ No newline at end of file diff --git a/agent/installer/ns_json/Contrib/nsJSON/LinkedList.c b/agent/installer/ns_json/Contrib/nsJSON/LinkedList.c new file mode 100644 index 00000000000..09c26e9b079 --- /dev/null +++ b/agent/installer/ns_json/Contrib/nsJSON/LinkedList.c @@ -0,0 +1,90 @@ +#include +#include "LinkedList.h" + +struct LinkedList* LinkedListCreate() +{ + return (struct LinkedList*)GlobalAlloc(GPTR, sizeof(struct LinkedList)); +} + +void LinkedListDestroy(struct LinkedList** ppList, LinkedListDestroyCallback callback) +{ + if (ppList && *ppList) + { + struct LinkedListNode* pNode = (*ppList)->First; + + while (pNode) + { + struct LinkedListNode* pNext = pNode->Next; + if (callback) + callback(pNode); + GlobalFree(pNode->Key); + GlobalFree(pNode); + pNode = pNext; + } + + GlobalFree(*ppList); + *ppList = NULL; + } +} + +void LinkedListDelete(struct LinkedList** ppList, const PTCHAR szKey) +{ + if (ppList && *ppList) + { + struct LinkedListNode* pNode = (*ppList)->First; + struct LinkedListNode* pPrev = NULL; + PTCHAR pszKey = szKey ? szKey : TEXT(""); + + while (pNode) + { + struct LinkedListNode* pNext = pNode->Next; + + if (lstrcmpi(pNode->Key, pszKey) == 0) + { + if (pPrev) + pPrev->Next = pNext; + + if ((*ppList)->First == pNode) + { + GlobalFree(*ppList); + *ppList = NULL; + } + + GlobalFree(pNode->Key); + GlobalFree(pNode); + break; + } + + pPrev = pNode; + pNode = pNext; + } + } +} + +struct LinkedListNode* LinkedListGet(struct LinkedList* pList, const PTCHAR szKey, const BOOL bCreate) +{ + if (pList) + { + struct LinkedListNode* pNode = pList->First; + PTCHAR pszKey = szKey ? szKey : TEXT(""); + + while (pNode) + { + if (lstrcmpi(pNode->Key, pszKey) == 0) + return pNode; + pNode = pNode->Next; + } + + if (bCreate) + { + pNode = (struct LinkedListNode*)GlobalAlloc(GPTR, sizeof(struct LinkedListNode)); + pNode->Key = (PTCHAR)GlobalAlloc(GPTR, sizeof(TCHAR) * (lstrlen(pszKey) + 1)); + lstrcpy(pNode->Key, pszKey); + pNode->Next = pList->First; + pList->First = pNode; + return pNode; + } + } + + return NULL; +} \ No newline at end of file diff --git a/agent/installer/ns_json/Contrib/nsJSON/LinkedList.h b/agent/installer/ns_json/Contrib/nsJSON/LinkedList.h new file mode 100644 index 00000000000..f077c2c6391 --- /dev/null +++ b/agent/installer/ns_json/Contrib/nsJSON/LinkedList.h @@ -0,0 +1,26 @@ +#ifndef __LinkedList_H__ +#define __LinkedList_H__ + +struct LinkedListNode +{ + PTCHAR Key; + PVOID Value; + struct LinkedListNode* Next; +}; + +struct LinkedList +{ + struct LinkedListNode* First; +}; + +struct LinkedList* LinkedListCreate(); + +typedef void (*LinkedListDestroyCallback)(struct LinkedListNode* pListNode); + +void LinkedListDestroy(struct LinkedList** ppList, LinkedListDestroyCallback callback); + +void LinkedListDelete(struct LinkedList** ppList, const PTCHAR szKey); + +struct LinkedListNode* LinkedListGet(struct LinkedList* pList, const PTCHAR szKey, const BOOL bCreate); + +#endif \ No newline at end of file diff --git a/agent/installer/ns_json/Contrib/nsJSON/api.h b/agent/installer/ns_json/Contrib/nsJSON/api.h new file mode 100644 index 00000000000..b8b78842f72 --- /dev/null +++ b/agent/installer/ns_json/Contrib/nsJSON/api.h @@ -0,0 +1,83 @@ +/* + * apih + * + * This file is a part of NSIS. + * + * Copyright (C) 1999-2013 Nullsoft and Contributors + * + * Licensed under the zlib/libpng license (the "License"); + * you may not use this file except in compliance with the License. + * + * Licence details can be found in the file COPYING. + * + * This software is provided 'as-is', without any express or implied + * warranty. + */ + +#ifndef _NSIS_EXEHEAD_API_H_ +#define _NSIS_EXEHEAD_API_H_ + +// Starting with NSIS 2.42, you can check the version of the plugin API in exec_flags->plugin_api_version +// The format is 0xXXXXYYYY where X is the major version and Y is the minor version (MAKELONG(y,x)) +// When doing version checks, always remember to use >=, ex: if (pX->exec_flags->plugin_api_version >= NSISPIAPIVER_1_0) {} + +#define NSISPIAPIVER_1_0 0x00010000 +#define NSISPIAPIVER_CURR NSISPIAPIVER_1_0 + +// NSIS Plug-In Callback Messages +enum NSPIM +{ + NSPIM_UNLOAD, // This is the last message a plugin gets, do final cleanup + NSPIM_GUIUNLOAD, // Called after .onGUIEnd +}; + +// Prototype for callbacks registered with extra_parameters->RegisterPluginCallback() +// Return NULL for unknown messages +// Should always be __cdecl for future expansion possibilities +typedef UINT_PTR (*NSISPLUGINCALLBACK)(enum NSPIM); + +// extra_parameters data structures containing other interesting stuff +// but the stack, variables and HWND passed on to plug-ins. +typedef struct +{ + int autoclose; + int all_user_var; + int exec_error; + int abort; + int exec_reboot; // NSIS_SUPPORT_REBOOT + int reboot_called; // NSIS_SUPPORT_REBOOT + int XXX_cur_insttype; // depreacted + int plugin_api_version; // see NSISPIAPIVER_CURR + // used to be XXX_insttype_changed + int silent; // NSIS_CONFIG_SILENT_SUPPORT + int instdir_error; + int rtl; + int errlvl; + int alter_reg_view; + int status_update; +} exec_flags_t; + +#ifndef NSISCALL +# define NSISCALL __stdcall +#endif + +typedef struct { + exec_flags_t *exec_flags; + int (NSISCALL *ExecuteCodeSegment)(int, HWND); + void (NSISCALL *validate_filename)(TCHAR *); + int (NSISCALL *RegisterPluginCallback)(HMODULE, NSISPLUGINCALLBACK); // returns 0 on success, 1 if already registered and < 0 on errors +} extra_parameters; + +// Definitions for page showing plug-ins +// See Ui.c to understand better how they're used + +// sent to the outer window to tell it to go to the next inner window +#define WM_NOTIFY_OUTER_NEXT (WM_USER+0x8) + +// custom pages should send this message to let NSIS know they're ready +#define WM_NOTIFY_CUSTOM_READY (WM_USER+0xd) + +// sent as wParam with WM_NOTIFY_OUTER_NEXT when user cancels - heed its warning +#define NOTIFY_BYE_BYE 'x' + +#endif /* _PLUGIN_H_ */ diff --git a/agent/installer/ns_json/Contrib/nsJSON/nsJSON.c b/agent/installer/ns_json/Contrib/nsJSON/nsJSON.c new file mode 100644 index 00000000000..58352480a43 --- /dev/null +++ b/agent/installer/ns_json/Contrib/nsJSON/nsJSON.c @@ -0,0 +1,1474 @@ +/* + nsJSON NSIS plug-in by Stuart Welch + v1.1.1.0 - 21st November 2017 +*/ + +#include +#include +#include "LinkedList.h" +#include "nsJSON.h" +#include "JSON.h" +#include "pluginapi.h" + +HANDLE g_hInstance; +struct LinkedList* g_pList = NULL; + +struct THREAD_PARAM +{ + struct JSON_NODE* pNode; + struct JSON_NODE* pRootNode; +}; + +static void NodeDelete(struct LinkedListNode* pListNode) +{ + JSON_Delete(&((struct JSON_NODE*)pListNode->Value), NULL); + pListNode->Value = NULL; +} + +static UINT_PTR PluginCallback(enum NSPIM msg) +{ + if (msg == NSPIM_UNLOAD) + { + LinkedListDestroy(&g_pList, NodeDelete); + } + return 0; +} + +BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved) +{ + g_hInstance = hInst; + return TRUE; +} + +static struct JSON_NODE* GetTreeNode(PTCHAR pszTree, BOOL bCreate) +{ + struct LinkedListNode* pListNode; + + if (!g_pList) + g_pList = LinkedListCreate(); + + pListNode = LinkedListGet(g_pList, pszTree, bCreate); + + if (bCreate && pListNode && !pListNode->Value) + pListNode->Value = JSON_Create(); + + return pListNode ? (struct JSON_NODE*)pListNode->Value : NULL; +} + +static struct JSON_NODE* PopTreeNode(PTCHAR pszArg, BOOL bCreate, BOOL* pbCreated) +{ + struct LinkedListNode* pListNode = NULL; + + if (!g_pList) + g_pList = LinkedListCreate(); + + if (pbCreated) + *pbCreated = FALSE; + + if (popstring(pszArg) == 0) + { + if (lstrcmpi(pszArg, TEXT("/tree")) == 0) + { + if (popstring(pszArg) == 0) + pListNode = LinkedListGet(g_pList, pszArg, bCreate); + } + else + { + pushstring(pszArg); + lstrcpy(pszArg, TEXT("")); + } + } + + if (!pListNode) + pListNode = LinkedListGet(g_pList, NULL, bCreate); + + if (bCreate && pListNode && !pListNode->Value) + { + pListNode->Value = JSON_Create(); + if (pbCreated) + *pbCreated = TRUE; + } + + return pListNode ? (struct JSON_NODE*)pListNode->Value : NULL; +} + +enum HttpWebRequestDataType +{ + WRDT_Default = 0, + WRDT_JSON = 1, + WRDT_Raw = 2, +}; + +static enum HttpWebRequestDataType GetHttpWebRequestDataType(struct JSON_NODE* pRootNode) +{ + PTCHAR pszDataType = JSON_GetQuotedValue(JSON_Get(pRootNode, TEXT("DataType"), FALSE), TEXT("")); + if (lstrcmpi(pszDataType, TEXT("JSON")) == 0) + return WRDT_JSON; + if (lstrcmpi(pszDataType, TEXT("Raw")) == 0) + return WRDT_Raw; + return WRDT_Default; +} + +#define _trim(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v' || c == '.') + +static void GetLastErrorMessage(PTCHAR pszErrorMessage, const PTCHAR szWin32Func, DWORD dwLastError) +{ + PTCHAR pszError; + int cchLastError; + + if (dwLastError >= 12001 && dwLastError <= 12156) + cchLastError = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, GetModuleHandleA("wininet.dll"), dwLastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&pszError, 0, NULL); + else + cchLastError = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwLastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&pszError, 0, NULL); + + if (cchLastError > 0) + { + int cchWin32Func = lstrlen(szWin32Func); + lstrcpy(pszErrorMessage, szWin32Func); + lstrcpy(pszErrorMessage + cchWin32Func, TEXT(": ")); + + for (cchLastError--; cchLastError >= 0 && _trim(pszError[cchLastError]); cchLastError--) + pszError[cchLastError] = '\0'; + lstrcpy(pszErrorMessage + cchWin32Func + 2, pszError); + + wsprintf(pszErrorMessage + cchWin32Func + 2 + cchLastError, TEXT(" (%lu)"), dwLastError); + } + + if (pszError) + LocalFree(pszError); +} + +static void SetLastErrorNode(struct JSON_NODE* pNode, const PTCHAR szWin32Func, DWORD dwLastError) +{ + PTCHAR pszError = (PTCHAR)GlobalAlloc(GPTR, 16 * sizeof(TCHAR)); + int cchLastError; + + if (pszError) + { + wsprintf(pszError, TEXT("%lu"), dwLastError); + JSON_SetEx(pNode, TEXT("ErrorCode"), FALSE, (PBYTE)pszError, JSF_NONE); + GlobalFree(pszError); + } + + if (dwLastError >= 12001 && dwLastError <= 12156) + cchLastError = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, GetModuleHandleA("wininet.dll"), dwLastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&pszError, 0, NULL); + else + cchLastError = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwLastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&pszError, 0, NULL); + + if (cchLastError > 0) + { + int cchWin32Func = lstrlen(szWin32Func); + PTCHAR pszErrorMessage = (PTCHAR)GlobalAlloc(GPTR, (cchLastError + cchWin32Func + 3) * sizeof(TCHAR)); + if (pszErrorMessage) + { + lstrcpy(pszErrorMessage, szWin32Func); + lstrcpy(pszErrorMessage + cchWin32Func, TEXT(": ")); + + for (cchLastError--; cchLastError >= 0 && _trim(pszError[cchLastError]); cchLastError--) + pszError[cchLastError] = '\0'; + lstrcpy(pszErrorMessage + cchWin32Func + 2, pszError); +#ifdef UNICODE + JSON_SetEx(pNode, TEXT("ErrorMessage"), FALSE, (PBYTE)pszErrorMessage, JSF_IS_RAW | JSF_IS_UNICODE); +#else + JSON_SetEx(pNode, TEXT("ErrorMessage"), FALSE, (PBYTE)pszErrorMessage, JSF_IS_RAW); +#endif + GlobalFree(pszErrorMessage); + } + } + + if (pszError) + LocalFree(pszError); +} + +static void DoHttpWebRequest(struct JSON_NODE* pNode, struct JSON_NODE* pRootNode) +{ + static PTCHAR accept[2] = { TEXT("*/*"), NULL }; + + PTCHAR pszUrl = JSON_GetQuotedValue(JSON_Get(pRootNode, TEXT("Url"), FALSE), NULL); + if (pszUrl) + { + PTCHAR pszAgentNode = JSON_GetQuotedValue(JSON_Get(pRootNode, TEXT("Agent"), FALSE), TEXT("nsJSON NSIS plug-in/1.0.x.x")), + pszAccessType = JSON_GetQuotedValue(JSON_Get(pRootNode, TEXT("AccessType"), FALSE), NULL), + pszProxyName = NULL, + pszProxyBypass = NULL; + struct JSON_NODE* pProxyNode = JSON_Get(pRootNode, TEXT("Proxy"), FALSE); + BOOL bSuccess = FALSE; + + DWORD dwAccessType = INTERNET_OPEN_TYPE_DIRECT; + if (pszAccessType) + { + if (lstrcmpi(pszAccessType, TEXT("PreConfig")) == 0) + { + dwAccessType = INTERNET_OPEN_TYPE_PRECONFIG; + } + else if (lstrcmpi(pszAccessType, TEXT("Proxy")) == 0) + { + if (pProxyNode) + { + pszProxyName = JSON_GetQuotedValue(JSON_Get(pProxyNode, TEXT("Server"), FALSE), NULL); + if (pszProxyName) + { + dwAccessType = INTERNET_OPEN_TYPE_PROXY; + pszProxyBypass = JSON_GetQuotedValue(JSON_Get(pProxyNode, TEXT("Bypass"), FALSE), NULL); + } + } + } + } + + HINTERNET hSession = InternetOpen(pszAgentNode, INTERNET_OPEN_TYPE_DIRECT, pszProxyName, pszProxyBypass, 0); + if (hSession != NULL) + { + LPURL_COMPONENTS pstUrlComp = (LPURL_COMPONENTS)GlobalAlloc(GPTR, sizeof(URL_COMPONENTS)); + if (pstUrlComp != NULL) + { + struct JSON_NODE* pParamsNode = JSON_Get(pRootNode, TEXT("Params"), FALSE); + BOOL bRawParams = pParamsNode && lstrcmpi(JSON_GetQuotedValue(JSON_Get(pRootNode, TEXT("ParamsType"), FALSE), TEXT("")), TEXT("Raw")) == 0; + PTCHAR pszParams = pParamsNode ? (bRawParams ? JSON_GetQuotedValue(pParamsNode, TEXT("")) : JSON_SerializeAlloc(pParamsNode->pValue, FALSE, TRUE)) : NULL; + + if (pParamsNode && !pszParams) + { + SetLastErrorNode(pNode, TEXT("JSON_SerializeAlloc"), GetLastError()); + } + else + { + pstUrlComp->dwStructSize = sizeof(URL_COMPONENTS); + pstUrlComp->dwUrlPathLength = pstUrlComp->dwHostNameLength = lstrlen(pszUrl) + 1; + + if (pParamsNode && pszParams && *pszParams) + pstUrlComp->dwUrlPathLength += lstrlen(pszParams) + 1; + + pstUrlComp->lpszUrlPath = (PTCHAR)GlobalAlloc(GPTR, pstUrlComp->dwUrlPathLength * sizeof(TCHAR)); + if (pstUrlComp->lpszUrlPath) + { + pstUrlComp->lpszHostName = (PTCHAR)GlobalAlloc(GPTR, pstUrlComp->dwHostNameLength * sizeof(TCHAR)); + if (pstUrlComp->lpszHostName) + { + if (InternetCrackUrl(pszUrl, 0, 0, pstUrlComp)) + { + HINTERNET hConnect = InternetConnect(hSession, pstUrlComp->lpszHostName, pstUrlComp->nPort, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); + if (hConnect) + { + PTCHAR pszVerb = JSON_GetQuotedValue(JSON_Get(pRootNode, TEXT("Verb"), FALSE), TEXT("GET")); + PTCHAR pszValue; + HINTERNET hRequest; + BOOL bEncoding; + + if (pParamsNode && pszParams && *pszParams) + { + lstrcpy(pstUrlComp->lpszUrlPath + pstUrlComp->dwUrlPathLength, TEXT("?")); + lstrcpy(pstUrlComp->lpszUrlPath + pstUrlComp->dwUrlPathLength + 1, pszParams); + } + + if (pProxyNode) + { + pszValue = JSON_GetQuotedValue(JSON_Get(pProxyNode, TEXT("Username"), FALSE), NULL); + if (pszValue) + InternetSetOption(hConnect, INTERNET_OPTION_PROXY_USERNAME, pszValue, lstrlen(pszValue)); + + pszValue = JSON_GetQuotedValue(JSON_Get(pProxyNode, TEXT("Password"), FALSE), NULL); + if (pszValue) + InternetSetOption(hConnect, INTERNET_OPTION_PROXY_PASSWORD, pszValue, lstrlen(pszValue)); + } + + if (bEncoding = JSON_IsTrue(JSON_Get(pRootNode, TEXT("Decoding"), FALSE))) + { + InternetSetOption(hConnect, INTERNET_OPTION_HTTP_DECODING, &bEncoding, sizeof(bEncoding)); + } + + pszValue = JSON_GetQuotedValue(JSON_Get(pRootNode, TEXT("Username"), FALSE), NULL); + if (pszValue) + { + InternetSetOption(hConnect, INTERNET_OPTION_USERNAME, pszValue, lstrlen(pszValue)); + } + + pszValue = JSON_GetQuotedValue(JSON_Get(pRootNode, TEXT("Password"), FALSE), NULL); + if (pszValue) + { + InternetSetOption(hConnect, INTERNET_OPTION_PASSWORD, pszValue, lstrlen(pszValue)); + } + + pszValue = JSON_GetQuotedValue(JSON_Get(pRootNode, TEXT("ConnectTimeout"), FALSE), NULL); + if (pszValue) + { + ULONG ulValue = myatou(pszValue); + InternetSetOption(hConnect, INTERNET_OPTION_CONNECT_TIMEOUT, &ulValue, sizeof(ulValue)); + } + + pszValue = JSON_GetQuotedValue(JSON_Get(pRootNode, TEXT("SendTimeout"), FALSE), NULL); + if (pszValue) + { + ULONG ulValue = myatou(pszValue); + InternetSetOption(hConnect, INTERNET_OPTION_SEND_TIMEOUT, &ulValue, sizeof(ulValue)); + } + + pszValue = JSON_GetQuotedValue(JSON_Get(pRootNode, TEXT("ReceiveTimeout"), FALSE), NULL); + if (pszValue) + { + ULONG ulValue = myatou(pszValue); + InternetSetOption(hConnect, INTERNET_OPTION_RECEIVE_TIMEOUT, &ulValue, sizeof(ulValue)); + } + + hRequest = HttpOpenRequest(hConnect, pszVerb, pstUrlComp->lpszUrlPath, NULL, NULL, accept, + INTERNET_FLAG_NO_CACHE_WRITE | + INTERNET_FLAG_NO_COOKIES | + INTERNET_FLAG_NO_UI | + INTERNET_FLAG_RELOAD | + INTERNET_FLAG_KEEP_CONNECTION | + (pstUrlComp->nScheme == INTERNET_SCHEME_HTTPS ? + INTERNET_FLAG_SECURE | + INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP | + INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS : 0), 0); + if (hRequest) + { + struct JSON_NODE* pDataNode = JSON_Get(pRootNode, TEXT("Data"), FALSE); + PTCHAR pszDataEncoding = JSON_GetQuotedValue(JSON_Get(pRootNode, TEXT("DataEncoding"), FALSE), NULL); + enum HttpWebRequestDataType eDataType = GetHttpWebRequestDataType(pRootNode); + struct JSON_NODE* pHeadersNode = JSON_Get(pRootNode, TEXT("Headers"), FALSE); + BOOL bRequestSent = FALSE; + + if (pHeadersNode) + { + if (pHeadersNode->eType == JNT_QUOTED_VALUE) + { + HttpAddRequestHeaders(hRequest, pHeadersNode->pszValue, -1L, 0); + } + + if (bEncoding) + { + HttpAddRequestHeaders(hRequest, TEXT("Accept-Encoding: gzip,deflate\r\n"), -1L, HTTP_ADDREQ_FLAG_ADD); + } + + if (lstrcmpi(pszVerb, TEXT("POST")) == 0) + { + if (eDataType == WRDT_JSON) + { + HttpAddRequestHeaders(hRequest, TEXT("Content-Type: application/json\r\n"), -1L, HTTP_ADDREQ_FLAG_ADD); + } + else + { + HttpAddRequestHeaders(hRequest, TEXT("Content-Type: application/x-www-form-urlencoded\r\n"), -1L, HTTP_ADDREQ_FLAG_ADD); + } + } + + if (pHeadersNode->eType == JNT_NODE) + { + pHeadersNode = pHeadersNode->pValue; + while (pHeadersNode) + { + int cchHeader = lstrlen(pHeadersNode->pszKey) + lstrlen(pHeadersNode->pszValue) + 4; + PTCHAR pszHeader = (PTCHAR)GlobalAlloc(GPTR, (cchHeader + 1) * sizeof(TCHAR)); + if (pszHeader) + { + lstrcpy(pszHeader, pHeadersNode->pszKey); + lstrcat(pszHeader, TEXT(": ")); + lstrcat(pszHeader, pHeadersNode->pszValue); + lstrcat(pszHeader, TEXT("\r\n")); + HttpAddRequestHeaders(hRequest, pszHeader, cchHeader, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE); + GlobalFree(pszHeader); + } + + pHeadersNode = pHeadersNode->pNext; + } + } + } + + if (pDataNode) + { + PTCHAR pszBuffer; + + if (eDataType == WRDT_JSON || eDataType == WRDT_Default) + { + pszBuffer = JSON_SerializeAlloc(pDataNode->pValue, FALSE, eDataType == WRDT_Default); + if (!pszBuffer) + { + SetLastErrorNode(pNode, TEXT("JSON_SerializeAlloc"), GetLastError()); + } + } + else + { + pszBuffer = JSON_GetQuotedValue(pDataNode, TEXT("")); + } + + if (pszBuffer) + { +#ifdef UNICODE + if (pszDataEncoding && lstrcmpi(pszDataEncoding, TEXT("Unicode")) == 0) + { + bRequestSent = HttpSendRequest(hRequest, NULL, 0, pszBuffer, lstrlen(pszBuffer) * sizeof(TCHAR)); + if (!bRequestSent) + SetLastErrorNode(pNode, TEXT("HttpSendRequest"), GetLastError()); + } + else + { + int cchConverted = lstrlen(pszBuffer); + PCHAR pszConverted = JSON_FromUnicode(pszBuffer, &cchConverted, CP_ACP); + if (pszConverted) + { + bRequestSent = HttpSendRequest(hRequest, NULL, 0, pszConverted, cchConverted); + if (!bRequestSent) + SetLastErrorNode(pNode, TEXT("HttpSendRequest"), GetLastError()); + GlobalFree(pszConverted); + } + } +#else + if (pszDataEncoding && lstrcmpi(pszDataEncoding, TEXT("Unicode")) == 0) + { + int cbUnicode = lstrlen(pszBuffer); + PWCHAR pszUnicode = JSON_ToUnicode(pszBuffer, &cbUnicode); + if (pszUnicode) + { + bRequestSent = HttpSendRequest(hRequest, NULL, 0, pszUnicode, cbUnicode); + if (!bRequestSent) + SetLastErrorNode(pNode, TEXT("HttpSendRequest"), GetLastError()); + GlobalFree(pszUnicode); + } + } + else + { + bRequestSent = HttpSendRequest(hRequest, NULL, 0, pszBuffer, lstrlen(pszBuffer) * sizeof(TCHAR)); + if (!bRequestSent) + SetLastErrorNode(pNode, TEXT("HttpSendRequest"), GetLastError()); + } +#endif + + GlobalFree(pszBuffer); + } + } + else + { + bRequestSent = HttpSendRequest(hRequest, NULL, 0, NULL, 0); + if (!bRequestSent) + SetLastErrorNode(pNode, TEXT("HttpSendRequest"), GetLastError()); + } + + if (bRequestSent) + { + DWORD dwSize; + PTCHAR pszStatusCode = NULL; + + if (InternetQueryDataAvailable(hRequest, &dwSize, 0, 0)) + { + PBYTE pbResponseBuffer = (PBYTE)GlobalAlloc(GPTR, dwSize + 1); + if (pbResponseBuffer) + { + DWORD dwBytesRead = 0; + if (InternetReadFile(hRequest, pbResponseBuffer, dwSize, &dwBytesRead)) + { + JSON_SetEx(pNode, TEXT("Output"), FALSE, pbResponseBuffer, + (JSON_IsTrue(JSON_Get(pRootNode, TEXT("UnicodeOutput"), FALSE)) ? JSF_IS_UNICODE : 0) | + (JSON_IsTrue(JSON_Get(pRootNode, TEXT("RawOutput"), FALSE)) ? JSF_IS_RAW : 0)); + } + else + { + SetLastErrorNode(pNode, TEXT("InternetReadFile"), GetLastError()); + } + + GlobalFree(pbResponseBuffer); + } + } + else + { + SetLastErrorNode(pNode, TEXT("InternetQueryDataAvailable"), GetLastError()); + } + + dwSize = 0; + if (!HttpQueryInfo(hRequest, HTTP_QUERY_STATUS_CODE, pszStatusCode, &dwSize, NULL) && GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + pszStatusCode = GlobalAlloc(GPTR, (dwSize + 1) * sizeof(TCHAR)); + if (pszStatusCode) + { + if (HttpQueryInfo(hRequest, HTTP_QUERY_STATUS_CODE, pszStatusCode, &dwSize, NULL)) + { +#ifdef UNICODE + JSON_SetEx(pNode, TEXT("StatusCode"), FALSE, (PBYTE)pszStatusCode, JSF_IS_UNICODE); +#else + JSON_SetEx(pNode, TEXT("StatusCode"), FALSE, (PBYTE)pszStatusCode, JSF_NONE); +#endif + } + + GlobalFree(pszStatusCode); + } + } + } + + InternetCloseHandle(hRequest); + } + else + { + SetLastErrorNode(pNode, TEXT("HttpOpenRequest"), GetLastError()); + } + + InternetCloseHandle(hConnect); + } + else + { + SetLastErrorNode(pNode, TEXT("InternetConnect"), GetLastError()); + } + } + else + { + SetLastErrorNode(pNode, TEXT("InternetCrackUrl"), GetLastError()); + } + + GlobalFree(pstUrlComp->lpszHostName); + } + + GlobalFree(pstUrlComp->lpszUrlPath); + } + + if (pParamsNode && pszParams && !bRawParams) + GlobalFree(pszParams); + } + + GlobalFree(pstUrlComp); + } + + InternetCloseHandle(hSession); + } + else + { + SetLastErrorNode(pNode, TEXT("InternetOpen"), GetLastError()); + } + } +} + +static DWORD WINAPI DoHttpWebRequestThreadProc(LPVOID lpParameter) +{ + struct THREAD_PARAM* ptp = (struct THREAD_PARAM*)lpParameter; + DoHttpWebRequest(ptp->pNode, ptp->pRootNode); + GlobalFree(ptp); + return 0; +} + +static void WriteInput(HANDLE hStdIn, struct JSON_NODE* pNode, BOOL bIsUnicode) +{ + DWORD dwBytesWritten; +#ifdef UNICODE + if (bIsUnicode) + { + WriteFile(hStdIn, pNode->pszValue, lstrlen(pNode->pszValue) * sizeof(TCHAR), &dwBytesWritten, NULL); + } + else + { + int cchValue = lstrlen(pNode->pszValue); + PCHAR pszConverted = JSON_FromUnicode(pNode->pszValue, &cchValue, CP_ACP); + if (pszConverted) + { + WriteFile(hStdIn, pszConverted, cchValue * sizeof(TCHAR), &dwBytesWritten, NULL); + GlobalFree(pszConverted); + } + } +#else + if (bIsUnicode) + { + int cchValue = lstrlenA(pNode->pszValue); + PWCHAR pwszConverted = JSON_ToUnicode(pNode->pszValue, &cchValue); + if (pwszConverted) + { + WriteFile(hStdIn, pNode->pszValue, lstrlen(pNode->pszValue) * sizeof(TCHAR), &dwBytesWritten, NULL); + GlobalFree(pwszConverted); + } + } + else + { + WriteFile(hStdIn, pNode->pszValue, lstrlen(pNode->pszValue) * sizeof(TCHAR), &dwBytesWritten, NULL); + } +#endif +} + +static void DoCreateProcess(struct JSON_NODE* pNode, struct JSON_NODE* pRootNode) +{ +#ifdef UNICODE + JSON_SetEx(pNode, TEXT("Output"), FALSE, (PBYTE)TEXT(""), JSF_IS_UNICODE); + JSON_SetEx(pNode, TEXT("ExitCode"), FALSE, (PBYTE)TEXT(""), JSF_IS_UNICODE); +#else + JSON_SetEx(pNode, TEXT("Output"), FALSE, (PBYTE)TEXT(""), JSF_NONE); + JSON_SetEx(pNode, TEXT("ExitCode"), FALSE, (PBYTE)TEXT(""), JSF_NONE); +#endif + + PTCHAR pszPath = JSON_GetQuotedValue(JSON_Get(pRootNode, TEXT("Path"), FALSE), NULL); + if (pszPath) + { + HANDLE hStdInRead = NULL, hStdInWrite = NULL, hStdOutRead = NULL, hStdOutWrite = NULL; + PBYTE pbOutputBuffer = (PBYTE)GlobalAlloc(GPTR, g_stringsize); + SECURITY_ATTRIBUTES saAttr; + saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + saAttr.bInheritHandle = TRUE; + saAttr.lpSecurityDescriptor = NULL; + + if (pbOutputBuffer) + { + if (CreatePipe(&hStdOutRead, &hStdOutWrite, &saAttr, 0) && + SetHandleInformation(hStdOutRead, HANDLE_FLAG_INHERIT, 0) && + CreatePipe(&hStdInRead, &hStdInWrite, &saAttr, 0) && + SetHandleInformation(hStdInWrite, HANDLE_FLAG_INHERIT, 0)) + { + PPROCESS_INFORMATION ppiProcInfo = (PPROCESS_INFORMATION)GlobalAlloc(GPTR, sizeof(PROCESS_INFORMATION)); + if (ppiProcInfo) + { + LPSTARTUPINFO psiStartInfo = (LPSTARTUPINFO)GlobalAlloc(GPTR, sizeof(STARTUPINFO)); + if (psiStartInfo) + { + struct JSON_NODE* pArgumentsNode = JSON_Get(pRootNode, TEXT("Arguments"), FALSE); + PTCHAR pszArguments = NULL; + + if (pArgumentsNode) + { + if (pArgumentsNode->eType == JNT_VALUE || pArgumentsNode->eType == JNT_QUOTED_VALUE) + { + pszArguments = pArgumentsNode->pszValue; + } + else if (pArgumentsNode->eType == JNT_ARRAY) + { + DWORD cchAlloc = 0; + struct JSON_NODE* pArrayNext = pArgumentsNode->pValue; + while (pArrayNext) + { + if (pArrayNext->eType == JNT_VALUE || pArrayNext->eType == JNT_QUOTED_VALUE) + cchAlloc += lstrlen(pArrayNext->pszValue) + 1; + pArrayNext = pArrayNext->pNext; + } + + if (cchAlloc > 0) + { + pszArguments = GlobalAlloc(GPTR, sizeof(TCHAR) * cchAlloc); + if (pszArguments) + { + DWORD dwPos = 0; + + pArrayNext = pArgumentsNode->pValue; + while (pArrayNext) + { + if (pArrayNext->eType == JNT_VALUE || pArrayNext->eType == JNT_QUOTED_VALUE) + { + lstrcpy(pszArguments + dwPos, pArrayNext->pszValue); + dwPos += lstrlen(pArrayNext->pszValue); + lstrcpy(pszArguments + dwPos, TEXT(" ")); + dwPos++; + } + pArrayNext = pArrayNext->pNext; + } + } + } + } + } + + psiStartInfo->cb = sizeof(STARTUPINFO); + psiStartInfo->hStdError = hStdOutWrite; + psiStartInfo->hStdOutput = hStdOutWrite; + psiStartInfo->hStdInput = hStdInRead; + psiStartInfo->dwFlags = STARTF_USESTDHANDLES; + + if (CreateProcess(pszPath, pszArguments, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, JSON_GetQuotedValue(JSON_Get(pRootNode, TEXT("WorkingDir"), FALSE), NULL), psiStartInfo, ppiProcInfo)) + { + struct JSON_NODE* pInputNode = JSON_Get(pRootNode, TEXT("Input"), FALSE); + DWORD dwBytesRead, dwTotalBytesRead = 0, dwValueBufferPos = 0; + PBYTE pbValueBuffer = NULL; + + CloseHandle(ppiProcInfo->hThread); + + if (pInputNode) + { + BOOL bIsUnicode = JSON_IsTrue(JSON_Get(pRootNode, TEXT("UnicodeInput"), FALSE)); + + if (pInputNode->eType == JNT_VALUE || pInputNode->eType == JNT_QUOTED_VALUE) + { + WriteInput(hStdInWrite, pInputNode, bIsUnicode); + } + else if (pInputNode->eType == JNT_ARRAY) + { + struct JSON_NODE* pArrayNext = pArgumentsNode->pValue; + while (pArrayNext) + { + if (pArrayNext->eType == JNT_VALUE || pArrayNext->eType == JNT_QUOTED_VALUE) + WriteInput(hStdInWrite, pArrayNext, bIsUnicode); + pArrayNext = pArrayNext->pNext; + } + } + } + + CloseHandle(hStdInWrite); + hStdInWrite = NULL; + CloseHandle(hStdOutWrite); + hStdOutWrite = NULL; + + while (ReadFile(hStdOutRead, pbOutputBuffer, g_stringsize, &dwBytesRead, NULL) && dwBytesRead != 0) + { + DWORD i; + + dwTotalBytesRead += dwBytesRead; + + if (pbValueBuffer) + { + pbValueBuffer = (PBYTE)GlobalReAlloc(pbValueBuffer, dwTotalBytesRead + sizeof(TCHAR), GMEM_ZEROINIT | GMEM_MOVEABLE); + } + else + { + pbValueBuffer = (PBYTE)GlobalAlloc(GPTR, dwBytesRead + sizeof(TCHAR)); + } + + if (!pbValueBuffer) + { + SetLastErrorNode(pNode, TEXT("DoCreateProcess"), GetLastError()); + break; + } + + for (i = 0; i < dwBytesRead; i++, dwValueBufferPos++) + { + pbValueBuffer[dwValueBufferPos] = pbOutputBuffer[i]; + } + } + + if (pbValueBuffer) + { + JSON_SetEx(pNode, TEXT("Output"), FALSE, pbValueBuffer, + (JSON_IsTrue(JSON_Get(pRootNode, TEXT("UnicodeOutput"), FALSE)) ? JSF_IS_UNICODE : 0) | + (JSON_IsTrue(JSON_Get(pRootNode, TEXT("RawOutput"), FALSE)) ? JSF_IS_RAW : 0)); + } + + if (GetExitCodeProcess(ppiProcInfo->hProcess, &dwBytesRead)) + { + PTCHAR pszExitCode = (PTCHAR)GlobalAlloc(GPTR, sizeof(TCHAR) * 11); + if (pszExitCode) + { + wsprintf(pszExitCode, TEXT("%lu"), dwBytesRead); +#ifdef UNICODE + JSON_SetEx(pNode, TEXT("ExitCode"), FALSE, (PBYTE)pszExitCode, JSF_IS_UNICODE); +#else + JSON_SetEx(pNode, TEXT("ExitCode"), FALSE, (PBYTE)pszExitCode, JSF_NONE); +#endif + GlobalFree(pszExitCode); + } + } + + CloseHandle(ppiProcInfo->hProcess); + } + + if (pArgumentsNode && pArgumentsNode->eType == JNT_ARRAY && pszArguments) + GlobalFree(pszArguments); + + GlobalFree(psiStartInfo); + } + + GlobalFree(ppiProcInfo); + } + } + + if (hStdInWrite != NULL) + CloseHandle(hStdInWrite); + if (hStdOutWrite != NULL) + CloseHandle(hStdOutWrite); + if (hStdInRead != NULL) + CloseHandle(hStdInRead); + if (hStdOutRead != NULL) + CloseHandle(hStdOutRead); + + GlobalFree(pbOutputBuffer); + } + } +} + +static DWORD WINAPI DoCreateProcessThreadProc(LPVOID lpParameter) +{ + struct THREAD_PARAM* ptp = (struct THREAD_PARAM*)lpParameter; + DoCreateProcess(ptp->pNode, ptp->pRootNode); + GlobalFree(ptp); + return 0; +} + +static BOOL CallFunc(LPTHREAD_START_ROUTINE func, struct JSON_NODE* pNode, PTCHAR pszTree) +{ + struct JSON_NODE* pRootNode = GetTreeNode(pszTree, FALSE); + BOOL bSuccess = FALSE; + + if (pRootNode) + { + struct THREAD_PARAM* ptp = (struct THREAD_PARAM*)GlobalAlloc(GPTR, sizeof(struct THREAD_PARAM)); + if (ptp) + { + ptp->pNode = pNode; + ptp->pRootNode = pRootNode; + + if (JSON_IsTrue(JSON_Get(pRootNode, TEXT("Async"), FALSE))) + { + HANDLE hThread = CreateThread(NULL, 0, func, ptp, 0, NULL); + if (hThread) + { + PTCHAR pszHandle = (PTCHAR)GlobalAlloc(GPTR, g_stringsize * sizeof(TCHAR)); + if (pszHandle) + { +#ifdef _WIN64 + wsprintf(pszHandle, TEXT("%Id"), hThread); +#else + wsprintf(pszHandle, TEXT("%d"), hThread); +#endif + +#ifdef UNICODE + JSON_SetEx(pRootNode, TEXT("Handle"), FALSE, (PBYTE)pszHandle, JSF_IS_UNICODE); +#else + JSON_SetEx(pRootNode, TEXT("Handle"), FALSE, (PBYTE)pszHandle, JSF_NONE); +#endif + GlobalFree(pszHandle); + bSuccess = TRUE; + } + } + else + { + GlobalFree(ptp); + } + } + else if (JSON_IsTrue(JSON_Get(pRootNode, TEXT("UIAsync"), FALSE))) + { + HANDLE hThread = CreateThread(NULL, 0, func, ptp, 0, NULL); + if (hThread) + { + BOOL bLoop = TRUE; + while (bLoop) + { + MSG msg; + if (MsgWaitForMultipleObjectsEx(1, &hThread, INFINITE, QS_ALLINPUT | QS_ALLPOSTMESSAGE, 0) != WAIT_OBJECT_0 + 1) + break; + + while (bLoop && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + if (msg.message == WM_QUIT) + { + PostMessage(msg.hwnd, msg.message, msg.wParam, msg.lParam); + bLoop = FALSE; + } + else + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + } + + CloseHandle(hThread); + bSuccess = TRUE; + } + } + else + { + func(ptp); + bSuccess = TRUE; + } + } + } + + return bSuccess; +} + +NSISFUNC(Serialize) +{ + DLL_INIT(); + { + BOOL bOK = FALSE; + + PTCHAR pszArg = (PTCHAR)GlobalAlloc(GPTR, sizeof(TCHAR) * string_size); + if (pszArg) + { + BOOL bIsFile = FALSE, bAsUnicode = FALSE, bFormat = FALSE; + struct JSON_NODE* pNode = PopTreeNode(pszArg, FALSE, NULL); + + while (popstring(pszArg) == 0) + { + if (lstrcmpi(pszArg, TEXT("/file")) == 0) + { + bIsFile = TRUE; + continue; + } + + if (lstrcmpi(pszArg, TEXT("/unicode")) == 0) + { + bAsUnicode = TRUE; + continue; + } + + if (lstrcmpi(pszArg, TEXT("/format")) == 0) + { + bFormat = TRUE; + continue; + } + + if (!bIsFile) + pushstring(pszArg); + break; + } + + if (pNode) + { +#ifdef UNICODE + if (!bIsFile) + bAsUnicode = TRUE; +#endif + if (JSON_Serialize(pNode, pszArg, string_size - 1, bIsFile, bAsUnicode, bFormat)) + { + if (!bIsFile) + pushstring(pszArg); + bOK = TRUE; + } + else + { + GetLastErrorMessage(pszArg, TEXT("JSON_Serialize"), GetLastError()); + pushstring(pszArg); + } + } + + GlobalFree(pszArg); + } + + if (!bOK) + extra->exec_flags->exec_error = 1; + } +} + +static void PushKeys(struct JSON_NODE* pNode) +{ + if (pNode->pNext) + PushKeys(pNode->pNext); + + if (pNode->pszKey) + pushstring(pNode->pszKey); + else + pushstring(pNode->pszValue); +} + +#define GET_ACTION_NOEXPAND 1 +#define GET_ACTION_KEY 2 +#define GET_ACTION_KEYS 3 +#define GET_ACTION_TYPE 4 +#define GET_ACTION_EXISTS 5 +#define GET_ACTION_COUNT 6 +#define GET_ACTION_ISEMPTY 7 + +NSISFUNC(Get) +{ + DLL_INIT(); + { + BOOL bOK = FALSE; + + PTCHAR pszArg = (PTCHAR)GlobalAlloc(GPTR, sizeof(TCHAR) * string_size); + if (pszArg) + { + struct JSON_NODE* pNode = PopTreeNode(pszArg, FALSE, NULL); + struct JSON_NODE* pPrev; + int nAction = 0; + BOOL bKeyIsIndex = FALSE; + + while (popstring(pszArg) == 0) + { + if (lstrcmpi(pszArg, TEXT("/noexpand")) == 0) + { + nAction = GET_ACTION_NOEXPAND; + continue; + } + + if (lstrcmpi(pszArg, TEXT("/key")) == 0) + { + nAction = GET_ACTION_KEY; + continue; + } + + if (lstrcmpi(pszArg, TEXT("/keys")) == 0) + { + nAction = GET_ACTION_KEYS; + continue; + } + + if (lstrcmpi(pszArg, TEXT("/type")) == 0) + { + nAction = GET_ACTION_TYPE; + continue; + } + + if (lstrcmpi(pszArg, TEXT("/exists")) == 0) + { + nAction = GET_ACTION_EXISTS; + continue; + } + + if (lstrcmpi(pszArg, TEXT("/count")) == 0) + { + nAction = GET_ACTION_COUNT; + continue; + } + + if (lstrcmpi(pszArg, TEXT("/isempty")) == 0) + { + nAction = GET_ACTION_ISEMPTY; + continue; + } + + pushstring(pszArg); + break; + } + + while (popstring(pszArg) == 0) + { + if (lstrcmpi(pszArg, TEXT("/end")) == 0) + break; + + if (lstrcmpi(pszArg, TEXT("/index")) == 0) + { + bKeyIsIndex = TRUE; + continue; + } + + if (pNode) + { + pPrev = pNode; + pNode = JSON_Next(&pPrev, pszArg, bKeyIsIndex, FALSE, NULL); + bKeyIsIndex = FALSE; + } + } + + if (pNode) + { + if (nAction == GET_ACTION_ISEMPTY) + { + pushstring(pNode->pValue ? TEXT("no") : TEXT("yes")); + } + else if (nAction == GET_ACTION_COUNT) + { + wsprintf(pszArg, TEXT("%d"), JSON_Count(pNode)); + pushstring(pszArg); + } + else if (nAction == GET_ACTION_EXISTS) + { + pushstring(TEXT("yes")); + } + else if (nAction == GET_ACTION_TYPE) + { + switch (pNode->eType) + { + case JNT_NODE: + pushstring(TEXT("node")); + break; + case JNT_ARRAY: + pushstring(TEXT("array")); + break; + case JNT_VALUE: + pushstring(TEXT("value")); + break; + case JNT_QUOTED_VALUE: + pushstring(TEXT("string")); + break; + } + } + else if (nAction == GET_ACTION_KEY) + { + if (pNode->pszKey) + pushstring(pNode->pszKey); + else + pushstring(pNode->pszValue); + } + else if (nAction == GET_ACTION_KEYS) + { + if (pNode->eType == JNT_NODE) + { + PushKeys(pNode->pValue); + wsprintf(pszArg, TEXT("%d"), JSON_Count(pNode)); + pushstring(pszArg); + } + else + { + pushstring(TEXT("0")); + } + } + else if (pNode->eType == JNT_VALUE) + { + pushstring(pNode->pszValue); + } + else if (pNode->eType == JNT_QUOTED_VALUE) + { + if (nAction == GET_ACTION_NOEXPAND) + { + pushstring(pNode->pszValue); + } + else + { + PTCHAR pszExpanded = JSON_Expand(pNode); + if (pszExpanded) + { + pushstring(pszExpanded); + GlobalFree(pszExpanded); + } + } + } + else if (pNode->pValue) + { + if (JSON_Serialize(pNode->pValue, pszArg, string_size - 1, FALSE, FALSE, FALSE)) + { + pushstring(pszArg); + bOK = TRUE; + } + else + { + GetLastErrorMessage(pszArg, TEXT("JSON_Serialize"), GetLastError()); + pushstring(pszArg); + } + } + else + { + pushstring(TEXT("")); + } + + bOK = TRUE; + } + else if (nAction == GET_ACTION_EXISTS) + { + pushstring(TEXT("no")); + bOK = TRUE; + } + else if (nAction == GET_ACTION_TYPE) + { + pushstring(TEXT("")); + bOK = TRUE; + } + else if (nAction == GET_ACTION_KEYS) + { + pushstring(TEXT("0")); + bOK = TRUE; + } + + GlobalFree(pszArg); + } + + if (!bOK) + extra->exec_flags->exec_error = 1; + } +} + +NSISFUNC(Set) +{ + DLL_INIT(); + { + BOOL bOK = FALSE; + + PTCHAR pszArg = (PTCHAR)GlobalAlloc(GPTR, sizeof(TCHAR) * string_size); + if (pszArg) + { + PTCHAR pszTree = (PTCHAR)GlobalAlloc(GPTR, sizeof(TCHAR) * string_size); + if (pszTree) + { + BOOL bCreated; + struct JSON_NODE* pTreeNode = PopTreeNode(pszTree, TRUE, &bCreated); + struct JSON_NODE* pNode = pTreeNode; + struct JSON_NODE* pPrev = NULL; + BOOL bKeyIsIndex = FALSE; + + while (popstring(pszArg) == 0) + { + if (lstrcmpi(pszArg, TEXT("/index")) == 0) + { + bKeyIsIndex = TRUE; + continue; + } + + if (lstrcmpi(pszArg, TEXT("/value")) == 0) + { + if (popstring(pszArg) == 0 && pNode) + { +#ifdef UNICODE + if (JSON_Set(pNode, (PBYTE)pszArg, JSF_IS_UNICODE)) +#else + if (JSON_Set(pNode, (PBYTE)pszArg, JSF_NONE)) +#endif + bOK = TRUE; + } + break; + } + + if (lstrcmpi(pszArg, TEXT("/file")) == 0) + { + if (popstring(pszArg) == 0) + { + if (lstrcmpi(pszArg, TEXT("/unicode")) == 0) + { + if (popstring(pszArg) == 0 && pNode) + { + if (JSON_Set(pNode, (PBYTE)pszArg, JSF_IS_FILE | JSF_IS_UNICODE)) + bOK = TRUE; + } + } + else + { + if (JSON_Set(pNode, (PBYTE)pszArg, JSF_IS_FILE)) + bOK = TRUE; + } + } + break; + } + + if (lstrcmpi(pszArg, TEXT("/http")) == 0) + { + if (popstring(pszArg) == 0 && pNode) + { + if (CallFunc(DoHttpWebRequestThreadProc, pNode, pszArg)) + bOK = TRUE; + } + break; + } + + if (lstrcmpi(pszArg, TEXT("/exec")) == 0) + { + if (popstring(pszArg) == 0 && pNode) + { + if (CallFunc(DoCreateProcessThreadProc, pNode, pszArg)) + bOK = TRUE; + } + break; + } + + if (pNode) + { + pPrev = pNode; + pNode = JSON_Next(&pPrev, pszArg, bKeyIsIndex, TRUE, &bCreated); + bKeyIsIndex = FALSE; + } + } + + if (!bOK && pNode && bCreated) + { + if (pNode == pTreeNode) + LinkedListDelete(&g_pList, pszTree); + JSON_Delete(&pNode, pPrev); + } + + GlobalFree(pszTree); + } + + GlobalFree(pszArg); + } + + if (!bOK) + extra->exec_flags->exec_error = 1; + } +} + +NSISFUNC(Delete) +{ + DLL_INIT(); + { + BOOL bOK = FALSE; + + PTCHAR pszArg = (PTCHAR)GlobalAlloc(GPTR, sizeof(TCHAR) * string_size); + if (pszArg) + { + PTCHAR pszTree = (PTCHAR)GlobalAlloc(GPTR, sizeof(TCHAR) * string_size); + if (pszTree) + { + struct JSON_NODE* pTreeNode = PopTreeNode(pszTree, FALSE, NULL); + struct JSON_NODE* pNode = pTreeNode; + struct JSON_NODE* pPrev = NULL; + BOOL bKeyIsIndex = FALSE; + + while (popstring(pszArg) == 0) + { + if (lstrcmpi(pszArg, TEXT("/end")) == 0) + break; + + if (lstrcmpi(pszArg, TEXT("/index")) == 0) + { + bKeyIsIndex = TRUE; + continue; + } + + if (pNode) + { + pPrev = pNode; + pNode = JSON_Next(&pPrev, pszArg, bKeyIsIndex, FALSE, NULL); + bKeyIsIndex = FALSE; + } + } + + if (pNode) + { + if (pNode == pTreeNode) + LinkedListDelete(&g_pList, pszTree); + JSON_Delete(&pNode, pPrev); + bOK = TRUE; + } + + GlobalFree(pszTree); + } + + GlobalFree(pszArg); + } + + if (!bOK) + extra->exec_flags->exec_error = 1; + } +} + +NSISFUNC(Quote) +{ + DLL_INIT(); + { + BOOL bOK = FALSE; + + PTCHAR pszArg = (PTCHAR)GlobalAlloc(GPTR, sizeof(TCHAR) * string_size); + if (pszArg) + { + enum JSON_ESCAPE_FLAGS eFlags = JEF_QUOTE; + + while (popstring(pszArg) == 0) + { + if (lstrcmpi(pszArg, TEXT("/unicode")) == 0) + { + eFlags |= JEF_ESCAPE_UNICODE; + continue; + } + + if (lstrcmpi(pszArg, TEXT("/always")) == 0) + { + eFlags |= JEF_ALWAYS_QUOTE; + continue; + } + + pushstring(pszArg); + break; + } + + if (popstring(pszArg) == 0) + { + PTCHAR pszQuoted = JSON_Escape(pszArg, eFlags); + if (pszQuoted) + { + pushstring(pszQuoted); + GlobalFree(pszQuoted); + bOK = TRUE; + } + } + + GlobalFree(pszArg); + } + + if (!bOK) + extra->exec_flags->exec_error = 1; + } +} + +NSISFUNC(Wait) +{ + DLL_INIT(); + { + BOOL bOK = FALSE; + + PTCHAR pszArg = (PTCHAR)GlobalAlloc(GPTR, sizeof(TCHAR) * string_size); + if (pszArg) + { + if (popstring(pszArg) == 0) + { + struct JSON_NODE* pNode = GetTreeNode(pszArg, FALSE); + if (pNode) + { + struct JSON_NODE* pPrev = pNode; + struct JSON_NODE* pHandleNode = JSON_Next(&pPrev, TEXT("Handle"), FALSE, FALSE, NULL); + if (pHandleNode && pHandleNode->eType == JNT_VALUE) + { + HANDLE hThread = (HANDLE)nsishelper_str_to_ptr(pHandleNode->pszValue); + if (hThread) + { + int nTimeout = -1; + + while (popstring(pszArg) == 0) + { + if (lstrcmpi(pszArg, TEXT("/timeout")) == 0) + { + if (popstring(pszArg) == 0) + nTimeout = myatoi(pszArg); + continue; + } + + pushstring(pszArg); + break; + } + + if (nTimeout >= 0) + { + if (WaitForSingleObject(hThread, nTimeout) == WAIT_TIMEOUT) + { + pushstring(TEXT("wait")); + } + else + { + pushstring(TEXT("")); + CloseHandle(hThread); + JSON_Delete(&pHandleNode, pPrev); + } + } + else + { + WaitForSingleObject(hThread, INFINITE); + CloseHandle(hThread); + JSON_Delete(&pHandleNode, pPrev); + } + + bOK = TRUE; + } + } + } + } + + GlobalFree(pszArg); + } + + if (!bOK) + extra->exec_flags->exec_error = 1; + } +} + +NSISFUNC(Sort) +{ + DLL_INIT(); + { + BOOL bOK = FALSE; + + PTCHAR pszArg = (PTCHAR)GlobalAlloc(GPTR, sizeof(TCHAR) * string_size); + if (pszArg) + { + struct JSON_NODE* pNode = PopTreeNode(pszArg, FALSE, NULL); + struct JSON_NODE* pPrev = NULL; + BOOL bKeyIsIndex = FALSE; + enum JSON_SORT_FLAGS eFlags = 0; + + while (popstring(pszArg) == 0) + { + if (lstrcmpi(pszArg, TEXT("/end")) == 0) + break; + + if (lstrcmpi(pszArg, TEXT("/index")) == 0) + { + bKeyIsIndex = TRUE; + continue; + } + + if (lstrcmpi(pszArg, TEXT("/options")) == 0) + { + eFlags = (enum JSON_SORT_FLAGS)popint(); + continue; + } + + if (pNode) + { + pPrev = pNode; + pNode = JSON_Next(&pPrev, pszArg, bKeyIsIndex, FALSE, NULL); + bKeyIsIndex = FALSE; + } + } + + if (pNode) + { + JSON_Sort(pNode, eFlags); + bOK = TRUE; + } + + GlobalFree(pszArg); + } + + if (!bOK) + extra->exec_flags->exec_error = 1; + } +} \ No newline at end of file diff --git a/agent/installer/ns_json/Contrib/nsJSON/nsJSON.h b/agent/installer/ns_json/Contrib/nsJSON/nsJSON.h new file mode 100644 index 00000000000..49339dfafe9 --- /dev/null +++ b/agent/installer/ns_json/Contrib/nsJSON/nsJSON.h @@ -0,0 +1,7 @@ +#ifndef __NSJSON_H__ +#define __NSJSON_H__ + +#define NSISFUNC(name) void __declspec(dllexport) name(HWND hWndParent, int string_size, TCHAR* variables, stack_t** stacktop, extra_parameters* extra) +#define DLL_INIT() EXDLL_INIT(); extra->RegisterPluginCallback((HMODULE)g_hInstance, PluginCallback) + +#endif \ No newline at end of file diff --git a/agent/installer/ns_json/Contrib/nsJSON/nsJSON.rc b/agent/installer/ns_json/Contrib/nsJSON/nsJSON.rc new file mode 100644 index 00000000000..058d46e6bfe Binary files /dev/null and b/agent/installer/ns_json/Contrib/nsJSON/nsJSON.rc differ diff --git a/agent/installer/ns_json/Contrib/nsJSON/nsJSON.sln b/agent/installer/ns_json/Contrib/nsJSON/nsJSON.sln new file mode 100644 index 00000000000..6992f3fe250 --- /dev/null +++ b/agent/installer/ns_json/Contrib/nsJSON/nsJSON.sln @@ -0,0 +1,97 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.24720.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nsJSON", "nsJSON.vcxproj", "{EC3375F9-B492-470B-8EA6-8F5F4A804BB7}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ConsoleApp", "ConsoleApp\ConsoleApp.vcxproj", "{6ECB05AC-F1A5-41F9-8880-431EEB8E2D7D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleAppDotNet", "ConsoleAppDotNet\ConsoleAppDotNet.csproj", "{DBAA5865-5EF1-4A17-BC19-B68D5E5C13F8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug Unicode|Any CPU = Debug Unicode|Any CPU + Debug Unicode|Win32 = Debug Unicode|Win32 + Debug Unicode|x64 = Debug Unicode|x64 + Debug|Any CPU = Debug|Any CPU + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release Unicode|Any CPU = Release Unicode|Any CPU + Release Unicode|Win32 = Release Unicode|Win32 + Release Unicode|x64 = Release Unicode|x64 + Release|Any CPU = Release|Any CPU + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EC3375F9-B492-470B-8EA6-8F5F4A804BB7}.Debug Unicode|Any CPU.ActiveCfg = Debug Unicode|Win32 + {EC3375F9-B492-470B-8EA6-8F5F4A804BB7}.Debug Unicode|Win32.ActiveCfg = Debug Unicode|Win32 + {EC3375F9-B492-470B-8EA6-8F5F4A804BB7}.Debug Unicode|Win32.Build.0 = Debug Unicode|Win32 + {EC3375F9-B492-470B-8EA6-8F5F4A804BB7}.Debug Unicode|x64.ActiveCfg = Debug Unicode|x64 + {EC3375F9-B492-470B-8EA6-8F5F4A804BB7}.Debug Unicode|x64.Build.0 = Debug Unicode|x64 + {EC3375F9-B492-470B-8EA6-8F5F4A804BB7}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {EC3375F9-B492-470B-8EA6-8F5F4A804BB7}.Debug|Win32.ActiveCfg = Debug|Win32 + {EC3375F9-B492-470B-8EA6-8F5F4A804BB7}.Debug|Win32.Build.0 = Debug|Win32 + {EC3375F9-B492-470B-8EA6-8F5F4A804BB7}.Debug|x64.ActiveCfg = Debug|x64 + {EC3375F9-B492-470B-8EA6-8F5F4A804BB7}.Debug|x64.Build.0 = Debug|x64 + {EC3375F9-B492-470B-8EA6-8F5F4A804BB7}.Release Unicode|Any CPU.ActiveCfg = Release Unicode|Win32 + {EC3375F9-B492-470B-8EA6-8F5F4A804BB7}.Release Unicode|Win32.ActiveCfg = Release Unicode|Win32 + {EC3375F9-B492-470B-8EA6-8F5F4A804BB7}.Release Unicode|Win32.Build.0 = Release Unicode|Win32 + {EC3375F9-B492-470B-8EA6-8F5F4A804BB7}.Release Unicode|x64.ActiveCfg = Release Unicode|x64 + {EC3375F9-B492-470B-8EA6-8F5F4A804BB7}.Release Unicode|x64.Build.0 = Release Unicode|x64 + {EC3375F9-B492-470B-8EA6-8F5F4A804BB7}.Release|Any CPU.ActiveCfg = Release|Win32 + {EC3375F9-B492-470B-8EA6-8F5F4A804BB7}.Release|Win32.ActiveCfg = Release|Win32 + {EC3375F9-B492-470B-8EA6-8F5F4A804BB7}.Release|Win32.Build.0 = Release|Win32 + {EC3375F9-B492-470B-8EA6-8F5F4A804BB7}.Release|x64.ActiveCfg = Release|x64 + {EC3375F9-B492-470B-8EA6-8F5F4A804BB7}.Release|x64.Build.0 = Release|x64 + {6ECB05AC-F1A5-41F9-8880-431EEB8E2D7D}.Debug Unicode|Any CPU.ActiveCfg = Release|x64 + {6ECB05AC-F1A5-41F9-8880-431EEB8E2D7D}.Debug Unicode|Any CPU.Build.0 = Release|x64 + {6ECB05AC-F1A5-41F9-8880-431EEB8E2D7D}.Debug Unicode|Win32.ActiveCfg = Debug|Win32 + {6ECB05AC-F1A5-41F9-8880-431EEB8E2D7D}.Debug Unicode|Win32.Build.0 = Debug|Win32 + {6ECB05AC-F1A5-41F9-8880-431EEB8E2D7D}.Debug Unicode|x64.ActiveCfg = Debug|x64 + {6ECB05AC-F1A5-41F9-8880-431EEB8E2D7D}.Debug Unicode|x64.Build.0 = Debug|x64 + {6ECB05AC-F1A5-41F9-8880-431EEB8E2D7D}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {6ECB05AC-F1A5-41F9-8880-431EEB8E2D7D}.Debug|Win32.ActiveCfg = Debug|Win32 + {6ECB05AC-F1A5-41F9-8880-431EEB8E2D7D}.Debug|Win32.Build.0 = Debug|Win32 + {6ECB05AC-F1A5-41F9-8880-431EEB8E2D7D}.Debug|x64.ActiveCfg = Debug|x64 + {6ECB05AC-F1A5-41F9-8880-431EEB8E2D7D}.Debug|x64.Build.0 = Debug|x64 + {6ECB05AC-F1A5-41F9-8880-431EEB8E2D7D}.Release Unicode|Any CPU.ActiveCfg = Release|x64 + {6ECB05AC-F1A5-41F9-8880-431EEB8E2D7D}.Release Unicode|Any CPU.Build.0 = Release|x64 + {6ECB05AC-F1A5-41F9-8880-431EEB8E2D7D}.Release Unicode|Win32.ActiveCfg = Release|Win32 + {6ECB05AC-F1A5-41F9-8880-431EEB8E2D7D}.Release Unicode|Win32.Build.0 = Release|Win32 + {6ECB05AC-F1A5-41F9-8880-431EEB8E2D7D}.Release Unicode|x64.ActiveCfg = Release|x64 + {6ECB05AC-F1A5-41F9-8880-431EEB8E2D7D}.Release Unicode|x64.Build.0 = Release|x64 + {6ECB05AC-F1A5-41F9-8880-431EEB8E2D7D}.Release|Any CPU.ActiveCfg = Release|Win32 + {6ECB05AC-F1A5-41F9-8880-431EEB8E2D7D}.Release|Win32.ActiveCfg = Release|Win32 + {6ECB05AC-F1A5-41F9-8880-431EEB8E2D7D}.Release|Win32.Build.0 = Release|Win32 + {6ECB05AC-F1A5-41F9-8880-431EEB8E2D7D}.Release|x64.ActiveCfg = Release|x64 + {6ECB05AC-F1A5-41F9-8880-431EEB8E2D7D}.Release|x64.Build.0 = Release|x64 + {DBAA5865-5EF1-4A17-BC19-B68D5E5C13F8}.Debug Unicode|Any CPU.ActiveCfg = Debug|Any CPU + {DBAA5865-5EF1-4A17-BC19-B68D5E5C13F8}.Debug Unicode|Any CPU.Build.0 = Debug|Any CPU + {DBAA5865-5EF1-4A17-BC19-B68D5E5C13F8}.Debug Unicode|Win32.ActiveCfg = Debug|Any CPU + {DBAA5865-5EF1-4A17-BC19-B68D5E5C13F8}.Debug Unicode|Win32.Build.0 = Debug|Any CPU + {DBAA5865-5EF1-4A17-BC19-B68D5E5C13F8}.Debug Unicode|x64.ActiveCfg = Debug|Any CPU + {DBAA5865-5EF1-4A17-BC19-B68D5E5C13F8}.Debug Unicode|x64.Build.0 = Debug|Any CPU + {DBAA5865-5EF1-4A17-BC19-B68D5E5C13F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DBAA5865-5EF1-4A17-BC19-B68D5E5C13F8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DBAA5865-5EF1-4A17-BC19-B68D5E5C13F8}.Debug|Win32.ActiveCfg = Debug|Any CPU + {DBAA5865-5EF1-4A17-BC19-B68D5E5C13F8}.Debug|Win32.Build.0 = Debug|Any CPU + {DBAA5865-5EF1-4A17-BC19-B68D5E5C13F8}.Debug|x64.ActiveCfg = Debug|Any CPU + {DBAA5865-5EF1-4A17-BC19-B68D5E5C13F8}.Debug|x64.Build.0 = Debug|Any CPU + {DBAA5865-5EF1-4A17-BC19-B68D5E5C13F8}.Release Unicode|Any CPU.ActiveCfg = Release|Any CPU + {DBAA5865-5EF1-4A17-BC19-B68D5E5C13F8}.Release Unicode|Any CPU.Build.0 = Release|Any CPU + {DBAA5865-5EF1-4A17-BC19-B68D5E5C13F8}.Release Unicode|Win32.ActiveCfg = Release|Any CPU + {DBAA5865-5EF1-4A17-BC19-B68D5E5C13F8}.Release Unicode|Win32.Build.0 = Release|Any CPU + {DBAA5865-5EF1-4A17-BC19-B68D5E5C13F8}.Release Unicode|x64.ActiveCfg = Release|Any CPU + {DBAA5865-5EF1-4A17-BC19-B68D5E5C13F8}.Release Unicode|x64.Build.0 = Release|Any CPU + {DBAA5865-5EF1-4A17-BC19-B68D5E5C13F8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DBAA5865-5EF1-4A17-BC19-B68D5E5C13F8}.Release|Any CPU.Build.0 = Release|Any CPU + {DBAA5865-5EF1-4A17-BC19-B68D5E5C13F8}.Release|Win32.ActiveCfg = Release|Any CPU + {DBAA5865-5EF1-4A17-BC19-B68D5E5C13F8}.Release|Win32.Build.0 = Release|Any CPU + {DBAA5865-5EF1-4A17-BC19-B68D5E5C13F8}.Release|x64.ActiveCfg = Release|Any CPU + {DBAA5865-5EF1-4A17-BC19-B68D5E5C13F8}.Release|x64.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/agent/installer/ns_json/Contrib/nsJSON/nsJSON.vcxproj b/agent/installer/ns_json/Contrib/nsJSON/nsJSON.vcxproj new file mode 100644 index 00000000000..77527006ad8 --- /dev/null +++ b/agent/installer/ns_json/Contrib/nsJSON/nsJSON.vcxproj @@ -0,0 +1,449 @@ + + + + + Debug Unicode + Win32 + + + Debug Unicode + x64 + + + Debug + Win32 + + + Debug + x64 + + + Release Unicode + Win32 + + + Release Unicode + x64 + + + Release + Win32 + + + Release + x64 + + + + {EC3375F9-B492-470B-8EA6-8F5F4A804BB7} + 10.0.15063.0 + + + + DynamicLibrary + Unicode + v140 + + + DynamicLibrary + Unicode + v140 + + + DynamicLibrary + MultiByte + v140 + + + DynamicLibrary + MultiByte + v140 + + + DynamicLibrary + Unicode + v140 + + + DynamicLibrary + Unicode + v140 + + + DynamicLibrary + MultiByte + v140 + + + DynamicLibrary + MultiByte + v140 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)..\..\Plugins\x86-ansi\ + false + false + $(SolutionDir)..\..\Plugins\x86-ansi\ + $(SolutionDir)..\..\Plugins\x86-unicode\ + false + false + false + false + $(SolutionDir)..\..\Plugins\x86-unicode\ + false + false + + + $(SolutionDir)..\..\Plugins\amd64-unicode\ + + + $(SolutionDir)..\..\Plugins\amd64-unicode\ + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + + + + + MultiThreadedDLL + false + + + Level3 + true + MinSpace + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + true + DllMain + + + MachineX86 + false + wininet.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + No + + + + + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + + + + + MultiThreadedDLL + false + + + Level3 + true + MinSpace + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + true + DllMain + + + false + wininet.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + No + + + + + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + + + + + WIN32;_DEBUG;_WINDOWS;_USRDLL;nsJSON_EXPORTS;%(PreprocessorDefinitions) + EnableFastChecks + + + Level3 + true + EditAndContinue + Disabled + MultiThreadedDebug + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + true + + + MachineX86 + + + false + wininet.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + + + + + WIN32;_DEBUG;_WINDOWS;_USRDLL;nsJSON_EXPORTS;%(PreprocessorDefinitions) + EnableFastChecks + + + Level3 + true + ProgramDatabase + Disabled + MultiThreadedDebug + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + true + + + + + false + wininet.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + + + + + WIN32;_DEBUG;_WINDOWS;_USRDLL;nsJSON_EXPORTS;%(PreprocessorDefinitions) + EnableFastChecks + + + Level3 + true + EditAndContinue + Disabled + MultiThreadedDebug + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + true + + + MachineX86 + + + wininet.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + + + + + WIN32;_DEBUG;_WINDOWS;_USRDLL;nsJSON_EXPORTS;%(PreprocessorDefinitions) + EnableFastChecks + + + Level3 + true + ProgramDatabase + Disabled + MultiThreadedDebug + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + true + + + + + wininet.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + + + + + MultiThreadedDLL + false + + + MinSpace + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + true + DllMain + + + MachineX86 + false + wininet.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + No + + + + + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + + + + + MultiThreadedDLL + false + + + MinSpace + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + true + DllMain + + + false + wininet.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + No + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/agent/installer/ns_json/Contrib/nsJSON/nsJSON.vcxproj.filters b/agent/installer/ns_json/Contrib/nsJSON/nsJSON.vcxproj.filters new file mode 100644 index 00000000000..42c994ea14f --- /dev/null +++ b/agent/installer/ns_json/Contrib/nsJSON/nsJSON.vcxproj.filters @@ -0,0 +1,56 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/agent/installer/ns_json/Contrib/nsJSON/nsis_tchar.h b/agent/installer/ns_json/Contrib/nsJSON/nsis_tchar.h new file mode 100644 index 00000000000..3e02d12f70b --- /dev/null +++ b/agent/installer/ns_json/Contrib/nsJSON/nsis_tchar.h @@ -0,0 +1,229 @@ +/* + * nsis_tchar.h + * + * This file is a part of NSIS. + * + * Copyright (C) 1999-2013 Nullsoft and Contributors + * + * This software is provided 'as-is', without any express or implied + * warranty. + * + * For Unicode support by Jim Park -- 08/30/2007 + */ + +// Jim Park: Only those we use are listed here. + +#pragma once + +#ifdef _UNICODE + +#ifndef _T +#define __T(x) L ## x +#define _T(x) __T(x) +#define _TEXT(x) __T(x) +#endif + +#ifndef _TCHAR_DEFINED +#define _TCHAR_DEFINED +#if !defined(_NATIVE_WCHAR_T_DEFINED) && !defined(_WCHAR_T_DEFINED) +typedef unsigned short TCHAR; +#else +typedef wchar_t TCHAR; +#endif +#endif + + +// program +#define _tenviron _wenviron +#define __targv __wargv + +// printfs +#define _ftprintf fwprintf +#define _sntprintf _snwprintf +#if (defined(_MSC_VER) && (_MSC_VER<=1310)) || defined(__MINGW32__) +# define _stprintf swprintf +#else +# define _stprintf _swprintf +#endif +#define _tprintf wprintf +#define _vftprintf vfwprintf +#define _vsntprintf _vsnwprintf +#if defined(_MSC_VER) && (_MSC_VER<=1310) +# define _vstprintf vswprintf +#else +# define _vstprintf _vswprintf +#endif + +// scanfs +#define _tscanf wscanf +#define _stscanf swscanf + +// string manipulations +#define _tcscat wcscat +#define _tcschr wcschr +#define _tcsclen wcslen +#define _tcscpy wcscpy +#define _tcsdup _wcsdup +#define _tcslen wcslen +#define _tcsnccpy wcsncpy +#define _tcsncpy wcsncpy +#define _tcsrchr wcsrchr +#define _tcsstr wcsstr +#define _tcstok wcstok + +// string comparisons +#define _tcscmp wcscmp +#define _tcsicmp _wcsicmp +#define _tcsncicmp _wcsnicmp +#define _tcsncmp wcsncmp +#define _tcsnicmp _wcsnicmp + +// upper / lower +#define _tcslwr _wcslwr +#define _tcsupr _wcsupr +#define _totlower towlower +#define _totupper towupper + +// conversions to numbers +#define _tcstoi64 _wcstoi64 +#define _tcstol wcstol +#define _tcstoul wcstoul +#define _tstof _wtof +#define _tstoi _wtoi +#define _tstoi64 _wtoi64 +#define _ttoi _wtoi +#define _ttoi64 _wtoi64 +#define _ttol _wtol + +// conversion from numbers to strings +#define _itot _itow +#define _ltot _ltow +#define _i64tot _i64tow +#define _ui64tot _ui64tow + +// file manipulations +#define _tfopen _wfopen +#define _topen _wopen +#define _tremove _wremove +#define _tunlink _wunlink + +// reading and writing to i/o +#define _fgettc fgetwc +#define _fgetts fgetws +#define _fputts fputws +#define _gettchar getwchar + +// directory +#define _tchdir _wchdir + +// environment +#define _tgetenv _wgetenv +#define _tsystem _wsystem + +// time +#define _tcsftime wcsftime + +#else // ANSI + +#ifndef _T +#define _T(x) x +#define _TEXT(x) x +#endif + +#ifndef _TCHAR_DEFINED +#define _TCHAR_DEFINED +typedef char TCHAR; +#endif + +// program +#define _tenviron environ +#define __targv __argv + +// printfs +#define _ftprintf fprintf +#define _sntprintf _snprintf +#define _stprintf sprintf +#define _tprintf printf +#define _vftprintf vfprintf +#define _vsntprintf _vsnprintf +#define _vstprintf vsprintf + +// scanfs +#define _tscanf scanf +#define _stscanf sscanf + +// string manipulations +#define _tcscat strcat +#define _tcschr strchr +#define _tcsclen strlen +#define _tcscnlen strnlen +#define _tcscpy strcpy +#define _tcsdup _strdup +#define _tcslen strlen +#define _tcsnccpy strncpy +#define _tcsrchr strrchr +#define _tcsstr strstr +#define _tcstok strtok + +// string comparisons +#define _tcscmp strcmp +#define _tcsicmp _stricmp +#define _tcsncmp strncmp +#define _tcsncicmp _strnicmp +#define _tcsnicmp _strnicmp + +// upper / lower +#define _tcslwr _strlwr +#define _tcsupr _strupr + +#define _totupper toupper +#define _totlower tolower + +// conversions to numbers +#define _tcstol strtol +#define _tcstoul strtoul +#define _tstof atof +#define _tstoi atoi +#define _tstoi64 _atoi64 +#define _tstoi64 _atoi64 +#define _ttoi atoi +#define _ttoi64 _atoi64 +#define _ttol atol + +// conversion from numbers to strings +#define _i64tot _i64toa +#define _itot _itoa +#define _ltot _ltoa +#define _ui64tot _ui64toa + +// file manipulations +#define _tfopen fopen +#define _topen _open +#define _tremove remove +#define _tunlink _unlink + +// reading and writing to i/o +#define _fgettc fgetc +#define _fgetts fgets +#define _fputts fputs +#define _gettchar getchar + +// directory +#define _tchdir _chdir + +// environment +#define _tgetenv getenv +#define _tsystem system + +// time +#define _tcsftime strftime + +#endif + +// is functions (the same in Unicode / ANSI) +#define _istgraph isgraph +#define _istascii __isascii + +#define __TFILE__ _T(__FILE__) +#define __TDATE__ _T(__DATE__) +#define __TTIME__ _T(__TIME__) diff --git a/agent/installer/ns_json/Contrib/nsJSON/pluginapi.c b/agent/installer/ns_json/Contrib/nsJSON/pluginapi.c new file mode 100644 index 00000000000..5d878606ce2 --- /dev/null +++ b/agent/installer/ns_json/Contrib/nsJSON/pluginapi.c @@ -0,0 +1,294 @@ +#include + +#include "pluginapi.h" + +#ifdef _countof +#define COUNTOF _countof +#else +#define COUNTOF(a) (sizeof(a)/sizeof(a[0])) +#endif + +unsigned int g_stringsize; +stack_t **g_stacktop; +TCHAR *g_variables; + +// utility functions (not required but often useful) + +int NSISCALL popstring(TCHAR *str) +{ + stack_t *th; + if (!g_stacktop || !*g_stacktop) return 1; + th=(*g_stacktop); + if (str) lstrcpy(str,th->text); + *g_stacktop = th->next; + GlobalFree((HGLOBAL)th); + return 0; +} + +int NSISCALL popstringn(TCHAR *str, int maxlen) +{ + stack_t *th; + if (!g_stacktop || !*g_stacktop) return 1; + th=(*g_stacktop); + if (str) lstrcpyn(str,th->text,maxlen?maxlen:g_stringsize); + *g_stacktop = th->next; + GlobalFree((HGLOBAL)th); + return 0; +} + +void NSISCALL pushstring(const TCHAR *str) +{ + stack_t *th; + if (!g_stacktop) return; + th=(stack_t*)GlobalAlloc(GPTR,(sizeof(stack_t)+(g_stringsize)*sizeof(TCHAR))); + lstrcpyn(th->text,str,g_stringsize); + th->next=*g_stacktop; + *g_stacktop=th; +} + +TCHAR* NSISCALL getuservariable(const int varnum) +{ + if (varnum < 0 || varnum >= __INST_LAST) return NULL; + return g_variables+varnum*g_stringsize; +} + +void NSISCALL setuservariable(const int varnum, const TCHAR *var) +{ + if (var != NULL && varnum >= 0 && varnum < __INST_LAST) + lstrcpy(g_variables + varnum*g_stringsize, var); +} + +#ifdef _UNICODE +int NSISCALL PopStringA(char* ansiStr) +{ + wchar_t* wideStr = (wchar_t*) GlobalAlloc(GPTR, g_stringsize*sizeof(wchar_t)); + int rval = popstring(wideStr); + WideCharToMultiByte(CP_ACP, 0, wideStr, -1, ansiStr, g_stringsize, NULL, NULL); + GlobalFree((HGLOBAL)wideStr); + return rval; +} + +int NSISCALL PopStringNA(char* ansiStr, int maxlen) +{ + int realLen = maxlen ? maxlen : g_stringsize; + wchar_t* wideStr = (wchar_t*) GlobalAlloc(GPTR, realLen*sizeof(wchar_t)); + int rval = popstringn(wideStr, realLen); + WideCharToMultiByte(CP_ACP, 0, wideStr, -1, ansiStr, realLen, NULL, NULL); + GlobalFree((HGLOBAL)wideStr); + return rval; +} + +void NSISCALL PushStringA(const char* ansiStr) +{ + wchar_t* wideStr = (wchar_t*) GlobalAlloc(GPTR, g_stringsize*sizeof(wchar_t)); + MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, wideStr, g_stringsize); + pushstring(wideStr); + GlobalFree((HGLOBAL)wideStr); + return; +} + +void NSISCALL GetUserVariableW(const int varnum, wchar_t* wideStr) +{ + lstrcpyW(wideStr, getuservariable(varnum)); +} + +void NSISCALL GetUserVariableA(const int varnum, char* ansiStr) +{ + wchar_t* wideStr = getuservariable(varnum); + WideCharToMultiByte(CP_ACP, 0, wideStr, -1, ansiStr, g_stringsize, NULL, NULL); +} + +void NSISCALL SetUserVariableA(const int varnum, const char* ansiStr) +{ + if (ansiStr != NULL && varnum >= 0 && varnum < __INST_LAST) + { + wchar_t* wideStr = g_variables + varnum * g_stringsize; + MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, wideStr, g_stringsize); + } +} + +#else +// ANSI defs +int NSISCALL PopStringW(wchar_t* wideStr) +{ + char* ansiStr = (char*) GlobalAlloc(GPTR, g_stringsize); + int rval = popstring(ansiStr); + MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, wideStr, g_stringsize); + GlobalFree((HGLOBAL)ansiStr); + return rval; +} + +int NSISCALL PopStringNW(wchar_t* wideStr, int maxlen) +{ + int realLen = maxlen ? maxlen : g_stringsize; + char* ansiStr = (char*) GlobalAlloc(GPTR, realLen); + int rval = popstringn(ansiStr, realLen); + MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, wideStr, realLen); + GlobalFree((HGLOBAL)ansiStr); + return rval; +} + +void NSISCALL PushStringW(wchar_t* wideStr) +{ + char* ansiStr = (char*) GlobalAlloc(GPTR, g_stringsize); + WideCharToMultiByte(CP_ACP, 0, wideStr, -1, ansiStr, g_stringsize, NULL, NULL); + pushstring(ansiStr); + GlobalFree((HGLOBAL)ansiStr); +} + +void NSISCALL GetUserVariableW(const int varnum, wchar_t* wideStr) +{ + char* ansiStr = getuservariable(varnum); + MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, wideStr, g_stringsize); +} + +void NSISCALL GetUserVariableA(const int varnum, char* ansiStr) +{ + lstrcpyA(ansiStr, getuservariable(varnum)); +} + +void NSISCALL SetUserVariableW(const int varnum, const wchar_t* wideStr) +{ + if (wideStr != NULL && varnum >= 0 && varnum < __INST_LAST) + { + char* ansiStr = g_variables + varnum * g_stringsize; + WideCharToMultiByte(CP_ACP, 0, wideStr, -1, ansiStr, g_stringsize, NULL, NULL); + } +} +#endif + +// playing with integers + +INT_PTR NSISCALL nsishelper_str_to_ptr(const TCHAR *s) +{ + INT_PTR v=0; + if (*s == _T('0') && (s[1] == _T('x') || s[1] == _T('X'))) + { + s++; + for (;;) + { + int c=*(++s); + if (c >= _T('0') && c <= _T('9')) c-=_T('0'); + else if (c >= _T('a') && c <= _T('f')) c-=_T('a')-10; + else if (c >= _T('A') && c <= _T('F')) c-=_T('A')-10; + else break; + v<<=4; + v+=c; + } + } + else if (*s == _T('0') && s[1] <= _T('7') && s[1] >= _T('0')) + { + for (;;) + { + int c=*(++s); + if (c >= _T('0') && c <= _T('7')) c-=_T('0'); + else break; + v<<=3; + v+=c; + } + } + else + { + int sign=0; + if (*s == _T('-')) sign++; else s--; + for (;;) + { + int c=*(++s) - _T('0'); + if (c < 0 || c > 9) break; + v*=10; + v+=c; + } + if (sign) v = -v; + } + + return v; +} + +unsigned int NSISCALL myatou(const TCHAR *s) +{ + unsigned int v=0; + + for (;;) + { + unsigned int c=*s++; + if (c >= _T('0') && c <= _T('9')) c-=_T('0'); + else break; + v*=10; + v+=c; + } + return v; +} + +int NSISCALL myatoi_or(const TCHAR *s) +{ + int v=0; + if (*s == _T('0') && (s[1] == _T('x') || s[1] == _T('X'))) + { + s++; + for (;;) + { + int c=*(++s); + if (c >= _T('0') && c <= _T('9')) c-=_T('0'); + else if (c >= _T('a') && c <= _T('f')) c-=_T('a')-10; + else if (c >= _T('A') && c <= _T('F')) c-=_T('A')-10; + else break; + v<<=4; + v+=c; + } + } + else if (*s == _T('0') && s[1] <= _T('7') && s[1] >= _T('0')) + { + for (;;) + { + int c=*(++s); + if (c >= _T('0') && c <= _T('7')) c-=_T('0'); + else break; + v<<=3; + v+=c; + } + } + else + { + int sign=0; + if (*s == _T('-')) sign++; else s--; + for (;;) + { + int c=*(++s) - _T('0'); + if (c < 0 || c > 9) break; + v*=10; + v+=c; + } + if (sign) v = -v; + } + + // Support for simple ORed expressions + if (*s == _T('|')) + { + v |= myatoi_or(s+1); + } + + return v; +} + +INT_PTR NSISCALL popintptr() +{ + TCHAR buf[128]; + if (popstringn(buf,COUNTOF(buf))) + return 0; + return nsishelper_str_to_ptr(buf); +} + +int NSISCALL popint_or() +{ + TCHAR buf[128]; + if (popstringn(buf,COUNTOF(buf))) + return 0; + return myatoi_or(buf); +} + +void NSISCALL pushintptr(INT_PTR value) +{ + TCHAR buffer[30]; + wsprintf(buffer, sizeof(void*) > 4 ? _T("%Id") : _T("%d"), value); + pushstring(buffer); +} diff --git a/agent/installer/ns_json/Contrib/nsJSON/pluginapi.h b/agent/installer/ns_json/Contrib/nsJSON/pluginapi.h new file mode 100644 index 00000000000..d6541123b81 --- /dev/null +++ b/agent/installer/ns_json/Contrib/nsJSON/pluginapi.h @@ -0,0 +1,104 @@ +#ifndef ___NSIS_PLUGIN__H___ +#define ___NSIS_PLUGIN__H___ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "api.h" +#include "nsis_tchar.h" + +#ifndef NSISCALL +# define NSISCALL __stdcall +#endif + +#define EXDLL_INIT() { \ + g_stringsize=string_size; \ + g_stacktop=stacktop; \ + g_variables=variables; } + +typedef struct _stack_t { + struct _stack_t *next; + TCHAR text[1]; // this should be the length of string_size +} stack_t; + +enum +{ +INST_0, // $0 +INST_1, // $1 +INST_2, // $2 +INST_3, // $3 +INST_4, // $4 +INST_5, // $5 +INST_6, // $6 +INST_7, // $7 +INST_8, // $8 +INST_9, // $9 +INST_R0, // $R0 +INST_R1, // $R1 +INST_R2, // $R2 +INST_R3, // $R3 +INST_R4, // $R4 +INST_R5, // $R5 +INST_R6, // $R6 +INST_R7, // $R7 +INST_R8, // $R8 +INST_R9, // $R9 +INST_CMDLINE, // $CMDLINE +INST_INSTDIR, // $INSTDIR +INST_OUTDIR, // $OUTDIR +INST_EXEDIR, // $EXEDIR +INST_LANG, // $LANGUAGE +__INST_LAST +}; + +extern unsigned int g_stringsize; +extern stack_t **g_stacktop; +extern TCHAR *g_variables; + +void NSISCALL pushstring(const TCHAR *str); +void NSISCALL pushintptr(INT_PTR value); +#define pushint(v) pushintptr((INT_PTR)(v)) +int NSISCALL popstring(TCHAR *str); // 0 on success, 1 on empty stack +int NSISCALL popstringn(TCHAR *str, int maxlen); // with length limit, pass 0 for g_stringsize +INT_PTR NSISCALL popintptr(); +#define popint() ( (int) popintptr() ) +int NSISCALL popint_or(); // with support for or'ing (2|4|8) +INT_PTR NSISCALL nsishelper_str_to_ptr(const TCHAR *s); +#define myatoi(s) ( (int) nsishelper_str_to_ptr(s) ) // converts a string to an integer +unsigned int NSISCALL myatou(const TCHAR *s); // converts a string to an unsigned integer, decimal only +int NSISCALL myatoi_or(const TCHAR *s); // with support for or'ing (2|4|8) +TCHAR* NSISCALL getuservariable(const int varnum); +void NSISCALL setuservariable(const int varnum, const TCHAR *var); + +#ifdef _UNICODE +#define PopStringW(x) popstring(x) +#define PushStringW(x) pushstring(x) +#define SetUserVariableW(x,y) setuservariable(x,y) + +int NSISCALL PopStringA(char* ansiStr); +void NSISCALL PushStringA(const char* ansiStr); +void NSISCALL GetUserVariableW(const int varnum, wchar_t* wideStr); +void NSISCALL GetUserVariableA(const int varnum, char* ansiStr); +void NSISCALL SetUserVariableA(const int varnum, const char* ansiStr); + +#else +// ANSI defs + +#define PopStringA(x) popstring(x) +#define PushStringA(x) pushstring(x) +#define SetUserVariableA(x,y) setuservariable(x,y) + +int NSISCALL PopStringW(wchar_t* wideStr); +void NSISCALL PushStringW(wchar_t* wideStr); +void NSISCALL GetUserVariableW(const int varnum, wchar_t* wideStr); +void NSISCALL GetUserVariableA(const int varnum, char* ansiStr); +void NSISCALL SetUserVariableW(const int varnum, const wchar_t* wideStr); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif//!___NSIS_PLUGIN__H___ diff --git a/agent/installer/ns_json/Contrib/nsJSON/resource.h b/agent/installer/ns_json/Contrib/nsJSON/resource.h new file mode 100644 index 00000000000..97a43f859b6 Binary files /dev/null and b/agent/installer/ns_json/Contrib/nsJSON/resource.h differ diff --git a/agent/installer/ns_json/Docs/nsJSON/Readme.txt b/agent/installer/ns_json/Docs/nsJSON/Readme.txt new file mode 100644 index 00000000000..5c66254164c --- /dev/null +++ b/agent/installer/ns_json/Docs/nsJSON/Readme.txt @@ -0,0 +1,564 @@ +nsJSON NSIS plug-in + +Author: Stuart 'Afrow UK' Welch +Date: 21st November 2017 +Version: 1.1.1.0 + +A JSON (JavaScript Object Notation) parser, manipulator and generator +plug-in for NSIS. + +See Examples\nsJSON\*. + +------------------------------------------------------------------------ +About JSON +------------------------------------------------------------------------ + + See http://www.json.org/ for information about JSON along with the + syntax and string escape sequences. + +------------------------------------------------------------------------ +Important information +------------------------------------------------------------------------ + + All plug-in functions set the NSIS error flag on error. For functions + that return a value on the stack, no item will be returned if the + error flag has been set. You can use IfErrors or ${If} ${Errors} to + check that a call has succeeded before Pop-ping a value, if any. + + The plug-in supports all escape sequences in string values: + \r, \n, \t, \b, \f, \", \\ and \uXXXX + + [NodePath], used throughout this readme, is any space-delimited list + of mixed node keys and indices (prefixed with /index). For example: + + { + "node1": { + "node2": false, + "node3": [ "Stuart", 1, { "node4": "Welch", "node5": "" }, 32.5, [ 0, "test", false ] ] + } + } + + This is a JSON snippet. "node2" is a child node of "node1". "node2" + has a Boolean value of false. "node3" is an array (denoted by square + brackets). The 3rd element within the array is another node. The 5th + element within the array is another array. + + These are examples of node paths within the JSON snippet: + + "node1" "node2" + -> The path for "node2" (value: false) + -> nsJSON::Get "node1" "node2" /end + + "node1" "node3" /index 0 + -> The path for the first array element in "node3" (value: "Stuart") + -> nsJSON::Get "node1" "node3" /index 0 /end + + "node1" "node3" /index 2 "node4" + -> The path for "node4" (value: "Welch") + -> nsJSON::Get "node1" "node3" /index 3 "node4" /end + + /index 0 "node3" /index 2 /index 0 + -> Also the path for "node4" (value: "Welch") + -> nsJSON::Get /index 0 /index 1 /index 3 /index 0 /end + + "node1" "node3" /index 4 /index -2 + -> The path for value "test" in the array; note the negative index + -> nsJSON::Get "node1" "node3" /index 4 /index -2 /end + + Node names containing double quotes are automatically escaped. If no + node path is given, the root node is used. + + Multiple JSON trees can be manipulated at the same time. Add + /tree Tree (where Tree is the tree name) before all other plug-in + arguments to specify which JSON tree you are manipulating. + +------------------------------------------------------------------------ +Reading JSON files +------------------------------------------------------------------------ + + nsJSON::Set [/tree Tree] [NodePath] /file [/unicode] "path\to\input.json" + + Loads the JSON from the given file into the given node. Specify + /unicode if the input file is Unicode. + +------------------------------------------------------------------------ + + nsJSON::Set [/tree Tree] /file [/unicode] "path\to\input.json" + + Loads the JSON from the given file into memory, overwriting any + existing JSON tree. Specify /unicode if the input file is Unicode. + +------------------------------------------------------------------------ +JSON from HTTP web requests +------------------------------------------------------------------------ + + nsJSON::Set [/tree Tree] [NodePath] /http ConfigTree + + Executes an HTTP web request and loads the JSON response into the + given node. The ConfigTree JSON tree specifies the web request + configuration to execute, described using JSON. Its possible values + are as follows... + + "Url": "http://..." + - The web request URL. This is required. + + "Verb": "GET" + - The request verb, such as GET or POST. Default is GET. + + "Params": "..." + - Optional parameters to append to the URL (after ?). + + "ParamsType": "..." + - The parameters type. Possible values are... + + Empty string/omitted (default) + - Parameters are given as JSON and will be sent as a standard + key/value pair string. Special characters will be URL-encoded + automatically. Arrays will be serialized as multiple keys of the + same name with a [] suffix. + + For example {"a": "Value1", "b": true, "c": "Value3"} becomes + a=Value1&b&c=Value3, and {"Array": [1, 2]} becomes + Array[]=1&Array[]=2. + + "Raw" + - Raw parameters are given as a string. + + "Data": "..." + - Optional request data to send (typically used with POST). + + "DataType": "..." + - The request data type. Possible values are... + + Empty string/omitted (default) + - Data is given as JSON and will be sent as a standard POST + key/value pair string. Special characters will be URL-encoded + automatically. Arrays will be serialized as multiple keys of the + same name with a [] suffix. + + For example {"a": "Value1", "b": true, "c": "Value3"} becomes + a=Value1&b&c=Value3, and {"Array": [1, 2]} becomes + Array[]=1&Array[]=2. + + "JSON" + - POST data is JSON and will be sent as-is (serialized JSON). + + "Raw" + - Raw POST data is given as a string. + + "DataEncoding": "..." + - Specifies the encoding to use for the POST data. Possible values + are... + + Empty string/omitted (default) + - Data is encoded as 1 byte per character. + + "Unicode" + - Data is encoded as 2 bytes per character. + + "Headers": "..." + - Additional headers to send, which will override these defaults... + * "Content-Type: application/x-www-form-urlencoded" is sent if "Verb" + is "POST" and "DataType" is "Raw". + * "Content-Type: application/json" is sent if "Verb" is "POST" and + "DataType" is "JSON". + * "Accept-Encoding: gzip,deflate" is sent if "Decoding" is set to + true. + + Specify headers as JSON, for example: + {"Content-Type": "text/plain", "a": "b"} + + + "Agent": "nsJSON NSIS plug-in/1.0.x.x" + - The request agent string. Default is shown. + + "Decoding": false + - Enables automatic GZIP decompression by sending the + "Accept-Encoding: gzip,deflate" request header. If the server responds + with a valid "Content-Encoding" header, the compressed data will be + decompressed automatically. + + "AccessType": "..." + - The connection access type. Possible values are... + + Empty string/omitted (default) + - Direct access (bypasses any proxy). + + "PreConfig" + - Use the internet configuration defined in the Windows registry. + + "Proxy" + - Use defined proxy configuration (see below). + + "Proxy": { "Server": "...", "Bypass": "...", Username": "...", "Password": "..." } + - Specifies the proxy configuration. The "Bypass" value is optional. + + "Username": "..." + - Username for HTTP authentication. + + "Password": "..." + - Password for HTTP authentication. + + "ConnectTimeout": "..." + - The initial connection timeout. A value of 0XFFFFFFFF will + disable the timeout. + + "SendTimeout": N + - The request send timeout. + + "ReceiveTimeout": N + - The response receive timeout. + + "UnicodeOutput": true + - The response must be read as Unicode rather than ASCII. + + "RawOutput": true + - The response must be read as raw text rather than JSON. + + "Async": true + - Perform the request asynchronously. You must use the Wait function + to wait or check if the request has finished. + + "UIAsync": true + - For performing the request in a page callback function. This will + ensure window messages are processed so that the UI does not become + unresponsive. + + After the request has finished, the node specified by NodePath will + contain the following values: + + "Output": ... + - The HTTP response as JSON. + + "StatusCode": N + - The HTTP status code. + + "ErrorCode": N + - The WinINet/Win32 error code on error. + + "ErrorMessage": "..." + - The WinINet/Win32 error message on error. + +------------------------------------------------------------------------ +JSON from console application execution +------------------------------------------------------------------------ + + nsJSON::Set [/tree Tree] [NodePath] /exec ConfigTree + + Executes a console application and loads the output into the given + node. The ConfigTree JSON tree specifies the console application to + execute, described using JSON. Its possible values are as follows... + + "Path": "$INSTDIR\ConsoleApp.exe" + - The path to the executable to be executed. This is required. + + "Arguments": ... + - The command line arguments. The value can be a string or an array of + strings. + + "WorkingDir": "..." + - The working/current directory. If not specified, the installer's + working directory will be used, which is $OUTDIR. + + "Input": ... + - The input to write to STDIN. The value can be a string or an array + of strings. + + "UnicodeInput": true + - The standard input must be written as Unicode rather than ASCII. + + "UnicodeOutput": true + - The standard output must be read as Unicode rather than ASCII. + + "RawOutput": true + - The standard output must be read as raw text rather than JSON. + + "Async": true + - Execute asynchronously. You must use the Wait function to wait or + check if the process has finished. + + "UIAsync": true + - For performing the execution in a page callback function. This will + ensure window messages are processed so that the UI does not become + unresponsive. + + After execution has finished, the node specified by NodePath will + contain the following values: + + "Output": ... + - The output of the console application, depending on the + RawOutput setting. + + "ExitCode": X + - The process exit code. + +------------------------------------------------------------------------ +Modifying JSON +------------------------------------------------------------------------ + + nsJSON::Set [/tree Tree] [NodePath] /value "Value" + + Sets the value of the given node. The value can be any single value or + it can be JSON code. The node will be created if it does not exist. + + -------------------------------------------------------------------- + + nsJSON::Delete [/tree Tree] [NodePath] /end + + Deletes the given tree or node. /end must be added to the end of the + list to prevent stack corruption. + + -------------------------------------------------------------------- + + nsJSON::Quote [/unicode] [/always] Value + Pop $Var + + Surrounds the given value with quotes if necessary and escapes any + characters that require it. The quoted value will be returned on the + stack. + + Optionally specify /unicode to escape non ASCII characters as well + although it is perfectly legal to include Unicode characters in JSON. + + Specify /always to always surround the input string in quotes even if + it is already quoted. + + -------------------------------------------------------------------- + + nsJSON::Sort [/tree Tree] [NodePath] [/options Options] /end + + Sorts the given node. Add up the following values for the optional + sort options: + + 1 = Sort in descending order. + 2 = Use numeric sort. + 4 = Sort case sensitively. + 8 = Sort by keys rather than by values. + 16 = Sort all nodes in the tree recursively. + +------------------------------------------------------------------------ +Reading JSON values +------------------------------------------------------------------------ + + nsJSON::Get [/tree Tree] [/noexpand] [NodePath] /end + Pop $Var + + Gets the value of the given node. The value returned will be JSON code + if the node is not a value-only node. Specify /noexpand when reading + quoted string values to stop escape sequences being expanded. /end + must be added to the end of the list to prevent stack corruption. + + -------------------------------------------------------------------- + + nsJSON::Get [/tree Tree] /type [NodePath] /end + Pop $Var + + Gets the value-type of the given node. It can be one of "node", + "array", "string" (quoted strings), "value" (which is all non-string + values such as integers, floats and Booleans) or an empty string if + the node does not exist. + + -------------------------------------------------------------------- + + nsJSON::Get [/tree Tree] /key [NodePath] /end + Pop $Var + + Gets the name (key) of the given node. + + -------------------------------------------------------------------- + + nsJSON::Get [/tree Tree] /keys [NodePath] /end + Pop $VarKeyCount + Pop $VarKey1 + Pop $VarKey2 + Pop $VarKeyN + + Gets the keys of the given node. $VarKeyCount will be the number of + keys pushed onto the stack (to be removed via Pop). + + -------------------------------------------------------------------- + + nsJSON::Get [/tree Tree] /exists [NodePath] /end + Pop $Var + + Determines whether or not the given node exists. $Var will be "yes" or + "no". + + -------------------------------------------------------------------- + + nsJSON::Get [/tree Tree] /count [NodePath] /end + Pop $Var + + Gets the number of child nodes for the given node or the number of + elements if the node is an array. + + -------------------------------------------------------------------- + + nsJSON::Get [/tree Tree] /isempty [NodePath] /end + Pop $Var + + Determines whether or not the given node is empty. $Var will be "yes" + or "no". An empty node is for example: "node": { } or "array": [ ]. + +------------------------------------------------------------------------ +Generating JSON +------------------------------------------------------------------------ + + nsJSON::Serialize [/tree Tree] [/format] + Pop $Var + + Serializes the current JSON tree into $Var. Add /format to apply + formatting to the output. The error flag is set if an error occurs. + + -------------------------------------------------------------------- + + nsJSON::Serialize [/tree Tree] [/format] /file [/unicode] "path\to\output.json" + + Serializes the current JSON tree into the given file. Add /format to + apply formatting to the output. Add /unicode to generate a Unicode + output file (applies to both ANSI and Unicode NSIS). + +------------------------------------------------------------------------ +Waiting for asynchronous tasks to finish +------------------------------------------------------------------------ + + nsJSON::Wait Tree [/timeout TimeoutInMilliseconds] + Pop $Var + + Checks whether or not the asynchonous task that is being ran under the + given JSON tree has finished. + + If /timeout is specified, the function will return after the + specified number of milliseconds; after which $Var will be "wait" if + the task has not finished; or an empty string otherwise. + + When /timeout is omitted, the function will wait indefinitely and + nothing will be pushed onto the stack when the task finishes. + +------------------------------------------------------------------------ +Change log +------------------------------------------------------------------------ + +1.1.1.0 - 21st November 2017 +* Fixed JSON with syntax errors still being parsed without setting the + error flag. +* Fixed Set function not replacing the root value if the value was an + array. +* Fixed Delete function not deleting the root node and tree. + +1.1.0.9 - 9th August 2017 +* Fixed access violation and stack overflow crashes in JSON_Delete, which + could occur on plug-in unload, Delete function call or when overwriting + existing nodes with the Set function. +* Fixed DoHttpWebRequest failing when POST data exceeded 2048 characters. +* Fixed DoCreateProcess failing to read process output when the output + exceeded 1024 characters. +* Delete function will now delete a complete node tree if no path is + given. + +1.1.0.8 - 8th January 2017 +* Added ErrorCode and ErrorMessage for HTTP requests for getting WinINet + or Win32 errors. +* Added Sort function. + +1.1.0.7 - 7th November 2016 +* Fixed /index for adding array elements with the Set function. +* Fixed file name being left on the stack after Serialize with /file. +* Added access type, proxy, authentication and timeout options for HTTP + requests. +* Added POST data encoding options for HTTP requests. +* HTTP request headers can be given as raw headers or as JSON key/value + pairs. +* Fixed a memory leak in JSON_SerializeAlloc and EscapePostData. +* POST parameters given as a JSON array was not escaped using + EscapePostData. + +1.1.0.6 - 14th October 2016 +* Output and ExitCode/StatusCode are always cleared for /exec and /http + calls on the Set function. + +1.1.0.5 - 10th August 2016 +* Empty value keys ("") were not included in serialized JSON. +* Serialize function popped one extra value from the stack. + +1.1.0.4 - 7th June 2016 +* Fixed incorrect flags used for HTTP requests. +* Added support for negative indices. +* Added console application execution for input and output. +* Added support for asynchronous HTTP requests and console application + execution. + +1.1.0.3 - 4th March 2016 +* Fixed crash for the Delete function when specifying a tree/path that + does not exist. +* Fixed Unicode build. +* Added /keys switch to Get function. + +1.1.0.2 - 9th December 2015 +* Get function /type switch returns an empty string if the node does not + exist. +* Added /always switch to Quote function which surrounds the input + string in quotes even if it is already quoted. + +1.1.0.1 - 23rd November 2015 +* Added Quote function. +* Added amd64-unicode build. + +1.1.0.0 - 19th April 2015 +* Support for multiple JSON trees. +* JSON via HTTP web requests. + +1.0.1.3 - 18th October 2014 +* Added UTF-16LE BOM, UTF-16BE BOM and UTF-8 signature detection for + input files (with UTF-16BE conversion to UTF-16LE). +* Fixed formatting errors for the Serialize function. +* Fixed closing bracket or curly brace not being included on Serialize + to stack when not using /format. +* Moved plug-in DLLs to x86-ansi and x86-unicode respectively for NSIS + 3.0. + +1.0.1.2 - 12th July 2014 +* Fixed crash on serialization to file for node values larger than 64KB. +* Fixed crash on serialization to stack for JSON larger than + NSIS_MAX_STRLEN. The JSON will now be truncated. + +1.0.1.1 - 29th March 2014 +* Fixed incorrect handling of escape character (\). + +1.0.1.0 - 28th August 2012 +* Added /unicode switch to the Serialize function. Output files for both + plug-in builds are now encoded in ANSI by default. +* Removed the Parse function in favour of Set /file [/unicode]. +* Added /type, /key, /exists, /count, /isempty to the Get function. +* Added /index switch for referencing nodes by index. + +1.0.0.2 - 15th August 2012 +* Fixed Unicode build parsing and serializing. + +1.0.0.1 - 1st July 2012 +* Fixed parsing of single digit numbers. +* Fixed Serialize not writing the output file when the stack isn't + empty. + +1.0.0.0 - 25th June 2012 +* First version. + +------------------------------------------------------------------------ +License +------------------------------------------------------------------------ + +This plug-in is provided 'as-is', without any express or implied +warranty. In no event will the author be held liable for any damages +arising from the use of this plug-in. + +Permission is granted to anyone to use this plug-in for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this plug-in must not be misrepresented; you must not + claim that you wrote the original plug-in. + If you use this plug-in in a product, an acknowledgment in the + product documentation would be appreciated but is not required. +2. Altered versions must be plainly marked as such, and must not be + misrepresented as being the original plug-in. +3. This notice may not be removed or altered from any distribution. \ No newline at end of file diff --git a/agent/installer/ns_json/Examples/nsJSON/Bin/ConsoleApp.exe b/agent/installer/ns_json/Examples/nsJSON/Bin/ConsoleApp.exe new file mode 100644 index 00000000000..b5a78faa3bd Binary files /dev/null and b/agent/installer/ns_json/Examples/nsJSON/Bin/ConsoleApp.exe differ diff --git a/agent/installer/ns_json/Examples/nsJSON/Bin/ConsoleAppDotNet.exe b/agent/installer/ns_json/Examples/nsJSON/Bin/ConsoleAppDotNet.exe new file mode 100644 index 00000000000..5dd03cdeb38 Binary files /dev/null and b/agent/installer/ns_json/Examples/nsJSON/Bin/ConsoleAppDotNet.exe differ diff --git a/agent/installer/ns_json/Examples/nsJSON/Bin/HttpWebRequest.php b/agent/installer/ns_json/Examples/nsJSON/Bin/HttpWebRequest.php new file mode 100644 index 00000000000..09cee51f94c --- /dev/null +++ b/agent/installer/ns_json/Examples/nsJSON/Bin/HttpWebRequest.php @@ -0,0 +1,33 @@ + 'No input given', 'SentHeaders' => getallheaders())); + exit; + } + + // Dump it... + @file_put_contents('POST.json', $input); + + // Do stuff with the POSTed JSON (read from HttpWebRequest->Data). + //$json->glossary->title = "nsJSON NSIS plug-in"; +} +// Data POSTed as key value pairs. +else +{ + // Dump it... + @file_put_contents('POST.txt', print_r($_POST, true)); + + //$myValue = $_POST['MyValue']; +} + +// Now respond with JSON (downloaded into HttpWebResponse). +echo json_encode(array('FirstName' => 'Stuart', 'LastName' => 'Welch', 'NickName' => 'Afrow UK', 'Email' => 'afrowuk@afrowsoft.co.uk')); + +?> \ No newline at end of file diff --git a/agent/installer/ns_json/Examples/nsJSON/ConsoleExec.nsi b/agent/installer/ns_json/Examples/nsJSON/ConsoleExec.nsi new file mode 100644 index 00000000000..7267bb6d54a --- /dev/null +++ b/agent/installer/ns_json/Examples/nsJSON/ConsoleExec.nsi @@ -0,0 +1,193 @@ +!include MUI2.nsh + +Name `nsJSON plug-in` +OutFile nsJSON_ConsoleExec.exe +RequestExecutionLevel user +ShowInstDetails show + +!define MUI_COMPONENTSPAGE_SMALLDESC +!define MUI_PAGE_CUSTOMFUNCTION_LEAVE ComponentsPage_Leave +!insertmacro MUI_PAGE_COMPONENTS +!insertmacro MUI_PAGE_INSTFILES + +!insertmacro MUI_LANGUAGE English + +Section + + CreateDirectory $EXEDIR\Output + +SectionEnd + +Section /o `Console App` NATIVE + + InitPluginsDir + StrCpy $R0 $PLUGINSDIR\ConsoleApp.exe + File /oname=$R0 Bin\ConsoleApp.exe + + nsJSON::Set /tree ConsoleExec /value `{ "Path": "$R0", "WorkingDir": "$PLUGINSDIR", "RawOutput": true }` + + ; Provide arguments as a single string or an array. + nsJSON::Set /tree ConsoleExec Arguments /value `[]` + nsJSON::Set /tree ConsoleExec Arguments /value `"arg1"` + nsJSON::Set /tree ConsoleExec Arguments /value `"arg2"` + + ; Provide input as a single string or an array. + nsJSON::Set /tree ConsoleExec Input /value `"hello"` + + ; Export the tree to file for debugging. + DetailPrint `Generate: $EXEDIR\Output\ConsoleExecInput.json from ConsoleExec` + nsJSON::Serialize /tree ConsoleExec /format /file $EXEDIR\Output\ConsoleExecInput.json + + ; Execute the console application. + DetailPrint `Exec: $R0` + nsJSON::Set /tree ConsoleExecOutput /exec ConsoleExec + + ; Save the output to file. + DetailPrint `Generate: $EXEDIR\Output\ConsoleExecOutput.json from ConsoleExecOutput` + nsJSON::Serialize /tree ConsoleExecOutput /format /file $EXEDIR\Output\ConsoleExecOutput.json + +SectionEnd + +Section /o `Async Console App` NATIVEASYNC + + InitPluginsDir + StrCpy $R0 $PLUGINSDIR\ConsoleApp.exe + File /oname=$R0 Bin\ConsoleApp.exe + + nsJSON::Set /tree ConsoleExec /value `{ "Async": true, "Path": "$R0", "WorkingDir": "$PLUGINSDIR", "RawOutput": true }` + + ; Provide arguments as a single string or an array. + nsJSON::Set /tree ConsoleExec Arguments /value `[]` + nsJSON::Set /tree ConsoleExec Arguments /value `"arg1"` + nsJSON::Set /tree ConsoleExec Arguments /value `"arg2"` + + ; Provide input as a single string or an array. + nsJSON::Set /tree ConsoleExec Input /value `"hello"` + + ; Export the tree to file for debugging. + DetailPrint `Generate: $EXEDIR\Output\AsyncConsoleExecInput.json from ConsoleExec` + nsJSON::Serialize /tree ConsoleExec /format /file $EXEDIR\Output\AsyncConsoleExecInput.json + + ; Execute the console application. + DetailPrint `Exec: $R0` + nsJSON::Set /tree AsyncConsoleExecOutput /exec ConsoleExec + + ; Wait until done. + ${Do} + Sleep 1000 + nsJSON::Wait ConsoleExec /timeout 0 + Pop $R0 + ${If} $R0 != wait + ${Break} + ${EndIf} + DetailPrint `Waiting...` + ${Loop} + + DetailPrint `Finished...` + + ; Save the output to file. + DetailPrint `Generate: $EXEDIR\Output\AsyncConsoleExecOutput.json from AsyncConsoleExecOutput` + nsJSON::Serialize /tree AsyncConsoleExecOutput /format /file $EXEDIR\Output\AsyncConsoleExecOutput.json + +SectionEnd + +Section /o `.NET Console App` DOTNET + + InitPluginsDir + StrCpy $R0 $PLUGINSDIR\ConsoleAppDotNet.exe + File /oname=$R0 Bin\ConsoleAppDotNet.exe + + nsJSON::Set /tree ConsoleExec /value `{ "Path": "$R0", "WorkingDir": "$PLUGINSDIR" }` + + ; Provide arguments as a single string or an array. + nsJSON::Set /tree ConsoleExec Arguments /value `[]` + nsJSON::Set /tree ConsoleExec Arguments /value `"arg1"` + nsJSON::Set /tree ConsoleExec Arguments /value `"arg2"` + + ; Provide input as a single string or an array. + nsJSON::Set /tree ConsoleExec Input /value `"hello"` + + ; Export the tree to file for debugging. + DetailPrint `Generate: $EXEDIR\Output\ConsoleExecDotNetInput.json from ConsoleExec` + nsJSON::Serialize /tree ConsoleExec /format /file $EXEDIR\Output\ConsoleExecDotNetInput.json + + ; Execute the console application. + DetailPrint `Exec: $R0` + nsJSON::Set /tree ConsoleExecOutput /exec ConsoleExec + + ; Save the output to file. + DetailPrint `Generate: $EXEDIR\Output\ConsoleExecDotNetOutput.json from ConsoleExecOutput` + nsJSON::Serialize /tree ConsoleExecOutput /format /file $EXEDIR\Output\ConsoleExecDotNetOutput.json + +SectionEnd + +Section /o `UI Thread Console App` UINATIVE + +SectionEnd + +Function ComponentsPage_Leave + + ${IfNot} ${SectionIsSelected} ${UINATIVE} + Return + ${EndIf} + + GetDlgItem $R0 $HWNDPARENT 1 + EnableWindow $R0 0 + GetDlgItem $R0 $HWNDPARENT 2 + EnableWindow $R0 0 + GetDlgItem $R0 $HWNDPARENT 3 + EnableWindow $R0 0 + FindWindow $R0 `#32770` `` $HWNDPARENT + GetDlgItem $R0 $R0 1032 + EnableWindow $R0 0 + + Banner::Show /set 76 `Executing ConsoleApp.exe` `Please wait...` + + InitPluginsDir + StrCpy $R0 $PLUGINSDIR\ConsoleApp.exe + File /oname=$R0 Bin\ConsoleApp.exe + + nsJSON::Set /tree ConsoleExec /value `{ "UIAsync": true, "Path": "$R0", "WorkingDir": "$PLUGINSDIR", "RawOutput": true }` + + ; Provide arguments as a single string or an array. + nsJSON::Set /tree ConsoleExec Arguments /value `[]` + nsJSON::Set /tree ConsoleExec Arguments /value `"arg1"` + nsJSON::Set /tree ConsoleExec Arguments /value `"arg2"` + + ; Provide input as a single string or an array. + nsJSON::Set /tree ConsoleExec Input /value `"hello"` + + ; Export the tree to file for debugging. + nsJSON::Serialize /tree ConsoleExec /format /file $EXEDIR\Output\UIConsoleExecInput.json + + ; Execute the console application. + nsJSON::Set /tree UIConsoleExecOutput /exec ConsoleExec + + ; Save the output to file. + nsJSON::Serialize /tree UIConsoleExecOutput /format /file $EXEDIR\Output\UIConsoleExecOutput.json + + Banner::Destroy + + GetDlgItem $R0 $HWNDPARENT 1 + EnableWindow $R0 1 + GetDlgItem $R0 $HWNDPARENT 2 + EnableWindow $R0 1 + GetDlgItem $R0 $HWNDPARENT 3 + EnableWindow $R0 1 + FindWindow $R0 `#32770` `` $HWNDPARENT + GetDlgItem $R0 $R0 1032 + EnableWindow $R0 1 + +FunctionEnd + +LangString NATIVEDesc ${LANG_ENGLISH} `Executes native console app with STDIN data and reads JSON from STDOUT` +LangString NATIVEASYNCDesc ${LANG_ENGLISH} `Executes native console app asynchronously with STDIN data and reads JSON from STDOUT` +LangString DOTNETDesc ${LANG_ENGLISH} `Executes .NET console app with STDIN data and reads JSON from STDOUT` +LangString UINATIVEDesc ${LANG_ENGLISH} `Executes native console app asynchronously while processing window messages` + +!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN + !insertmacro MUI_DESCRIPTION_TEXT ${NATIVE} $(NATIVEDesc) + !insertmacro MUI_DESCRIPTION_TEXT ${NATIVEASYNC} $(NATIVEASYNCDesc) + !insertmacro MUI_DESCRIPTION_TEXT ${DOTNET} $(DOTNETDesc) + !insertmacro MUI_DESCRIPTION_TEXT ${UINATIVE} $(UINATIVEDesc) +!insertmacro MUI_FUNCTION_DESCRIPTION_END \ No newline at end of file diff --git a/agent/installer/ns_json/Examples/nsJSON/Example.nsi b/agent/installer/ns_json/Examples/nsJSON/Example.nsi new file mode 100644 index 00000000000..b0e7623cec9 --- /dev/null +++ b/agent/installer/ns_json/Examples/nsJSON/Example.nsi @@ -0,0 +1,509 @@ +!include MUI2.nsh + +Name `nsJSON plug-in` +OutFile nsJSON_Example.exe +RequestExecutionLevel user +ShowInstDetails show + +!define MUI_COMPONENTSPAGE_SMALLDESC +!insertmacro MUI_PAGE_COMPONENTS +!insertmacro MUI_PAGE_INSTFILES + +!insertmacro MUI_LANGUAGE English + +Section + + CreateDirectory $EXEDIR\Output + +SectionEnd + +Section /o `Parse Example1.json` EXAMPLE1 + + ; Input: Example1.json; output: Example1.json. + nsJSON::Set /file $EXEDIR\Input\Example1.json + nsJSON::Serialize /format /file $EXEDIR\Output\Example1.json + DetailPrint `Generate: $EXEDIR\Output\Example1.json` + +SectionEnd + +Section /o `Convert Example1_Unicode.json (no BOM)` EXAMPLE1B + + ; Use the /unicode switch if the input file is Unicode. + nsJSON::Set /file /unicode $EXEDIR\Input\Example1_Unicode.json + + ; Generate an ANSII output file. + nsJSON::Serialize /format /file $EXEDIR\Output\Example1B_ASCII.json + DetailPrint `Generate: $EXEDIR\Output\Example1B_ASCII.json` + + ; Generate a Unicode output file. + nsJSON::Serialize /format /file /unicode $EXEDIR\Output\Example1B_Unicode.json + DetailPrint `Generate: $EXEDIR\Output\Example1B_Unicode.json` + +SectionEnd + +Section /o `Convert Example1_Unicode_UTF16BE.json (BOM)` EXAMPLE1C + + ; Use the /unicode switch if the input file is Unicode. + nsJSON::Set /file /unicode $EXEDIR\Input\Example1_Unicode_UTF16BE.json + + ; Generate an ANSII output file. + nsJSON::Serialize /format /file $EXEDIR\Output\Example1C_ASCII.json + DetailPrint `Generate: $EXEDIR\Output\Example1C_ASCII.json` + + ; Generate a Unicode output file. + nsJSON::Serialize /format /file /unicode $EXEDIR\Output\Example1C_Unicode.json + DetailPrint `Generate: $EXEDIR\Output\Example1C_Unicode.json` + +SectionEnd + +Section /o `Convert Example1_Unicode_UTF16LE.json (BOM)` EXAMPLE1D + + ; Use the /unicode switch if the input file is Unicode. + nsJSON::Set /file /unicode $EXEDIR\Input\Example1_Unicode_UTF16LE.json + + ; Generate an ANSII output file. + nsJSON::Serialize /format /file $EXEDIR\Output\Example1D_ASCII.json + DetailPrint `Generate: $EXEDIR\Output\Example1D_ASCII.json` + + ; Generate a Unicode output file. + nsJSON::Serialize /format /file /unicode $EXEDIR\Output\Example1D_Unicode.json + DetailPrint `Generate: $EXEDIR\Output\Example1D_Unicode.json` + +SectionEnd + +Section /o `Convert Example1_Unicode_UTF8.json (sig)` EXAMPLE1E + + ; No /unicode switch is used for UTF8. + nsJSON::Set /file $EXEDIR\Input\Example1_Unicode_UTF8.json + + ; Generate an ANSII output file. + nsJSON::Serialize /format /file $EXEDIR\Output\Example1_ASCII.json + DetailPrint `Generate: $EXEDIR\Output\Example1_ASCII.json` + + ; Generate a Unicode output file. + nsJSON::Serialize /format /file /unicode $EXEDIR\Output\Example1_Unicode.json + DetailPrint `Generate: $EXEDIR\Output\Example1_Unicode.json` + +SectionEnd + +Section /o `Parse Example2.json` EXAMPLE2 + + ; Input: Example2.json; output: Example2.json. + nsJSON::Set /file $EXEDIR\Input\Example2.json + nsJSON::Serialize /format /file $EXEDIR\Output\Example2.json + DetailPrint `Generate: $EXEDIR\Output\Example2.json` + +SectionEnd + +Section /o `Parse Example3.json` EXAMPLE3 + + ; Input: Example3.json; output: Example3.json. + nsJSON::Set /file $EXEDIR\Input\Example3.json + nsJSON::Serialize /format /file $EXEDIR\Output\Example3.json + DetailPrint `Generate: $EXEDIR\Output\Example3.json` + +SectionEnd + +Section /o `Parse Example4.json` EXAMPLE4 + + ; Input: Example4.json; output: Example4.json. + nsJSON::Set /file $EXEDIR\Input\Example4.json + nsJSON::Serialize /format /file $EXEDIR\Output\Example4.json + DetailPrint `Generate: $EXEDIR\Output\Example4.json` + +SectionEnd + +Section /o `Parse Example5.json` EXAMPLE5 + + ; Input: Example5.json; output: Example5.json. + nsJSON::Set /file $EXEDIR\Input\Example5.json + nsJSON::Serialize /format /file $EXEDIR\Output\Example5.json + DetailPrint `Generate: $EXEDIR\Output\Example5.json` + +SectionEnd + +Section /o `Parse Example5.json (via $$R0)` EXAMPLE5B + + ; Input: Example5.json; output: Example5.json. + nsJSON::Set /file $EXEDIR\Input\Example5.json + nsJSON::Serialize /format + Pop $R0 + FileOpen $R1 $EXEDIR\Output\Example5B.json w + FileWrite $R1 $R0 + FileClose $R1 + DetailPrint `Generate: $EXEDIR\Output\Example5B.json` + +SectionEnd + +Section /o `Generate Example6.json` EXAMPLE6 + + nsJSON::Set /value `{}` + nsJSON::Set `html` `head` `title` /value `"Example6"` + + ; Build an array using individual calls. + nsJSON::Set `html` `body` `h1` /value `[]` + nsJSON::Set `html` `body` `h1` /value `"Hello,\tmy name is"` + nsJSON::Set `html` `body` `h1` `i` /value `"Stuart."` + nsJSON::Set `html` `body` `h1` /value `"Howdy"` + nsJSON::Set `html` `body` `h1` /value `"!"` + nsJSON::Set `html` `body` `h1` /value `[ true, "hello", false ]` + + ; Build an array using a JSON string. + nsJSON::Set `html` `body` `h2` /value `[ "I like", { "u": { "i" : "programming" } }, "very much!" ]` + + ; Quotes in node keys are allowed; they are escaped automatically. + nsJSON::Set `html` `body` `a href="http://www.afrowsoft.co.uk"` /value `"My website!"` + + ; Open the file below in Notepad. + nsJSON::Serialize /format /file $EXEDIR\Output\Example6.json + DetailPrint `Generate: $EXEDIR\Output\Example6.json` + +SectionEnd + +Section /o `Reading from Example1.json` EXAMPLE7 + + nsJSON::Set /file $EXEDIR\Input\Example1.json + + ; Read quoted string value. + ClearErrors + nsJSON::Get `glossary` `GlossDiv` `GlossList` `GlossEntry` `GlossTerm` /end + ${IfNot} ${Errors} + Pop $R0 + DetailPrint `glossary->GlossDiv->GlossList->GlossEntry->GlossTerm = $R0` + ${EndIf} + + ; Read quoted string value with escaping. + ClearErrors + nsJSON::Set `glossary` `GlossDiv` `GlossList` `GlossEntry` `GlossDef` `para2` /value `"A meta-markup language, used to create markup languages\r\nsuch as DocBook."` + nsJSON::Get `glossary` `GlossDiv` `GlossList` `GlossEntry` `GlossDef` `para2` /end + ${IfNot} ${Errors} + Pop $R0 + DetailPrint `glossary->GlossDiv->GlossList->GlossEntry->GlossDef->para2 = $R0` + ${EndIf} + + ; Read quoted string value without expanding escape sequences. + ClearErrors + nsJSON::Set `glossary` `GlossDiv` `GlossList` `GlossEntry` `GlossDef` `para3` /value `"A meta-markup language, used to create markup languages\r\nsuch as DocBook."` + nsJSON::Get /noexpand `glossary` `GlossDiv` `GlossList` `GlossEntry` `GlossDef` `para3` /end + ${IfNot} ${Errors} + Pop $R0 + DetailPrint `glossary->GlossDiv->GlossList->GlossEntry->GlossDef->para3 = $R0` + ${EndIf} + + ; Read the value of an array (returns a comma delimited list). + ClearErrors + nsJSON::Get `glossary` `GlossDiv` `GlossList` `GlossEntry` `GlossDef` `GlossSeeAlso` /end + ${IfNot} ${Errors} + Pop $R0 + DetailPrint `glossary->GlossDiv->GlossList->GlossEntry->GlossDef->GlossSeeAlso = $R0` + ${EndIf} + + ; Try reading a node that does not exist. + ClearErrors + nsJSON::Get `glossary` `GlossDiv` `GlossList` `GlossEntry` `GlossDef` `GlossSeeAlso2` /end + ${IfNot} ${Errors} + Pop $R0 + DetailPrint `glossary->GlossDiv->GlossList->GlossEntry->GlossDef->GlossSeeAlso2 = $R0` + ${Else} + DetailPrint `glossary->GlossDiv->GlossList->GlossEntry->GlossDef->GlossSeeAlso2 = Does not exist!` + ${EndIf} + + ; Try reading an array element that does not exist. + ClearErrors + nsJSON::Get `glossary` `GlossDiv` `GlossList` `GlossEntry` `GlossDef` `GlossSeeAlso` 99 /end + ${IfNot} ${Errors} + Pop $R0 + DetailPrint `glossary->GlossDiv->GlossList->GlossEntry->GlossDef->GlossSeeAlso->#99 = $R0` + ${Else} + DetailPrint `glossary->GlossDiv->GlossList->GlossEntry->GlossDef->GlossSeeAlso->#99 = Does not exist!` + ${EndIf} + +SectionEnd + +Section /o `Arrays test` EXAMPLE8 + + nsJSON::Set /value `{}` + + ; You can add an array this way. + nsJSON::Set `array1` /value `[ "value 1", "value 2", { "value 3": "node value" }, "value 4", 5 ]` + + ; Inspect array1. + nsJSON::Get `array1` /end + Pop $R0 + DetailPrint `array1 = [$R0]` + + ; Or you can build it this way. + nsJSON::Set `array2` /value `[]` + nsJSON::Set `array2` /value `"value 1"` + nsJSON::Set `array2` /value `"value 2"` + nsJSON::Set `array2` `value 3` /value `"node value"` + nsJSON::Set `array2` /value `"value 4"` + nsJSON::Set `array2` /value `5` + + ; You cannot add the same value again. + nsJSON::Set `array2` /value `5` + + ; More. + nsJSON::Set `array2` /value `blah1` + nsJSON::Set `array2` /value `blah2` + + ; Inspect array2. + nsJSON::Get `array2` /end + Pop $R0 + DetailPrint `array2 = [$R0]` + + ; Does an array element exist at the given index? + nsJSON::Get /exists `array2` /index 0 /end + Pop $R0 + DetailPrint `array2[0] exists? = $R0` + ${If} $R0 == yes + nsJSON::Get `array2` /index 0 /end + Pop $R0 + DetailPrint `array2[0] = $R0` + ${EndIf} + + ; Does an array element exist at the given index? + nsJSON::Get /exists `array2` /index -2 /end + Pop $R0 + DetailPrint `array2[-2] exists? = $R0` + ${If} $R0 == yes + nsJSON::Get `array2` /index -2 /end + Pop $R0 + DetailPrint `array2[-2] = $R0` + ${EndIf} + + ; Does an array element exist that matches the value? + nsJSON::Get /exists `array2` `5` /end + Pop $R0 + DetailPrint `array2->5 exists? = $R0` + + ; Does an array element exist at the given index? + nsJSON::Get /exists `array2` /index 6 /end + Pop $R0 + DetailPrint `array2[6] exists? = $R0` + + ; Open Example8_1.json to see what it now looks like. + nsJSON::Serialize /format /file $EXEDIR\Output\Example8_1.json + DetailPrint `Generate: $EXEDIR\Output\Example8_1.json` + + ; Now delete the element at the given index. + nsJSON::Delete `array1` /index 2 `value 3` /end + DetailPrint `Delete: array1[2]->value 3` + nsJSON::Delete `array2` /index 5 /end + DetailPrint `Delete: array2[5]` + + ; Now delete the elements with the given values. + nsJSON::Delete `array1` `value 1` /end + DetailPrint `Delete: array1->value 1` + nsJSON::Delete `array2` `value 2` /end + DetailPrint `Delete: array2->value 2` + + ; Inspect array1. + nsJSON::Get `array1` /end + Pop $R0 + DetailPrint `array1 = [$R0]` + + ; Inspect array2. + nsJSON::Get `array2` /end + Pop $R0 + DetailPrint `array2 = [$R0]` + + ; Open Example8_2.json to see what it now looks like. + nsJSON::Serialize /format /file $EXEDIR\Output\Example8_2.json + DetailPrint `Generate: $EXEDIR\Output\Example8_2.json` + +SectionEnd + +Section /o `Node iteration test` EXAMPLE9 + + nsJSON::Set /file $EXEDIR\Input\Example4.json + + ; Get the node count. + nsJSON::Get /count `web-app` `servlet` /index 0 `init-param` /end + Pop $R0 + + DetailPrint `Node web-app->servlet[0]->init-param contains $R0 children:` + ${For} $R1 0 $R0 + + nsJSON::Get /key `web-app` `servlet` /index 0 `init-param` /index $R1 /end + Pop $R2 + nsJSON::Get `web-app` `servlet` /index 0 `init-param` /index $R1 /end + Pop $R3 + nsJSON::Get /type `web-app` `servlet` /index 0 `init-param` /index $R1 /end + Pop $R4 + DetailPrint `$R2 = $R3 (type: $R4)` + + ${Next} + +SectionEnd + +Section /o `Load Example5.json into Example4.json` EXAMPLE10 + + ; Input: Example5.json; output: Example5.json. + nsJSON::Set /file $EXEDIR\Input\Example5.json + nsJSON::Set `menu` `example4` /file $EXEDIR\Input\Example4.json + nsJSON::Serialize /format /file $EXEDIR\Output\Example10.json + DetailPrint `Generate: $EXEDIR\Output\Example10.json` + +SectionEnd + +Section /o `Copies Preferences.json into PreferencesNew.json` EXAMPLE11 + + ; Input: Preferences.json; output: PreferencesNew.json. + nsJSON::Set /file $EXEDIR\Input\Preferences.json + nsJSON::Serialize /format /file $EXEDIR\Output\PreferencesNew.json + DetailPrint `Generate: $EXEDIR\Output\PreferencesNew.json` + +SectionEnd + +Section /o `Copies Preferences2.json into Preferences2New.json` EXAMPLE12 + + ; Input: Preferences2.json; output: Preferences2New.json. + nsJSON::Set /file $EXEDIR\Input\Preferences2.json + nsJSON::Serialize /format /file $EXEDIR\Output\Preferences2New.json + DetailPrint `Generate: $EXEDIR\Output\Preferences2New.json` + +SectionEnd + +Section /o `Buffer overflow` EXAMPLE13 + + ; Input: Example2.json. + nsJSON::Set /file $EXEDIR\Input\Example2.json + nsJSON::Serialize /format + Pop $R0 + StrLen $R1 $R0 + DetailPrint `Output length: $R1` + MessageBox MB_OK $R0 + +SectionEnd + +Section /o `Get tests` EXAMPLE14 + + nsJSON::Set /value `{ "a": "a", "b": 1, "c": {} }` + nsJSON::Serialize /format + Pop $R0 + DetailPrint `Test: $R0` + + nsJSON::Get /key /index 0 /end + Pop $R0 + DetailPrint `Key at index 0: $R0` + + nsJSON::Get /keys /end + Pop $R0 + DetailPrint `Total keys: $R0` + StrCpy $R1 0 + ${DoWhile} $R0 > 0 + Pop $R2 + DetailPrint `Key at index $R1: $R2` + IntOp $R0 $R0 - 1 + IntOp $R1 $R1 + 1 + ${Loop} + + nsJSON::Get /type /index 0 /end + Pop $R0 + DetailPrint `Type at index 0: $R0` + + nsJSON::Get /exists /index 0 /end + Pop $R0 + DetailPrint `Index 0 exists?: $R0` + + nsJSON::Get /count /end + Pop $R0 + DetailPrint `Count: $R0` + + nsJSON::Get /isempty /end + Pop $R0 + DetailPrint `Is empty?: $R0` + + nsJSON::Get /isempty /index 2 /end + Pop $R0 + DetailPrint `Is empty at index 2?: $R0` + + ClearErrors + nsJSON::Get /isempty /index 99 /end + IfErrors 0 +2 + DetailPrint `Is empty at index 99?: Error flag is set` + +SectionEnd + +Section /o `Delete tests` EXAMPLE15 + + nsJSON::Set /value `{ "a": "a", "b": 1, "c": {} }` + nsJSON::Serialize /format + Pop $R0 + DetailPrint `Test: $R0` + + nsJSON::Delete a /end + Pop $R0 + DetailPrint `Delete key "a": $R0` + + nsJSON::Serialize /format + Pop $R0 + DetailPrint `Now: $R0` + + ClearErrors + nsJSON::Delete /index 99 /end + IfErrors 0 +2 + DetailPrint `Delete at index 99: Error flag is set` + +SectionEnd + +Section /o `Empty keys` EXAMPLE16 + + nsJSON::Set /value `{ "": "a", 1, "c": {} }` + nsJSON::Serialize /format + Pop $R0 + DetailPrint `Test: $R0` + + nsJSON::Set a "" /value `"abc"` + nsJSON::Serialize /format + Pop $R0 + DetailPrint `Test: $R0` + +SectionEnd + +LangString Example1Desc ${LANG_ENGLISH} `Parses Example1.json and then generates Output\Example1.json` +LangString Example1BDesc ${LANG_ENGLISH} `Parses Example1_Unicode.json (no BOM) and then generates Unicode and ASCII copies` +LangString Example1CDesc ${LANG_ENGLISH} `Parses Example1_Unicode_UTF16BE.json (BOM) and then generates Unicode and ASCII copies` +LangString Example1DDesc ${LANG_ENGLISH} `Parses Example1_Unicode_UTF16LE.json (BOM) and then generates Unicode and ASCII copies` +LangString Example1EDesc ${LANG_ENGLISH} `Parses Example1_Unicode_UTF8.json (sig) and then generates Unicode and ASCII copies` +LangString Example2Desc ${LANG_ENGLISH} `Parses Example2.json and then generates Output\Example2.json` +LangString Example3Desc ${LANG_ENGLISH} `Parses Example3.json and then generates Output\Example3.json` +LangString Example4Desc ${LANG_ENGLISH} `Parses Example4.json and then generates Output\Example4.json` +LangString Example5Desc ${LANG_ENGLISH} `Parses Example5.json and then generates Output\Example5.json` +LangString Example5BDesc ${LANG_ENGLISH} `Parses Example5.json and then generates Output\Example5B.json using $$R0` +LangString Example6Desc ${LANG_ENGLISH} `Generates Output\Example6.json using Parse, Set and Serialize` +LangString Example7Desc ${LANG_ENGLISH} `Parses Example1.json and then reads values from the tree using Get` +LangString Example8Desc ${LANG_ENGLISH} `Tests JSON array manipulation while generating Output\Example8.json` +LangString Example9Desc ${LANG_ENGLISH} `Iterates through some nodes in Example4.json by index` +LangString Example10Desc ${LANG_ENGLISH} `Parses Example5.json into Example4.json and then generates Output\Example10.json` +LangString Example11Desc ${LANG_ENGLISH} `Parses Preferences.json and then generates Output\PreferencesNew.json` +LangString Example12Desc ${LANG_ENGLISH} `Parses Preferences2.json and then generates Output\Preferences2New.json` +LangString Example13Desc ${LANG_ENGLISH} `Parses Example2.json (size>NSIS_MAX_STRLEN) and outputs the result.` +LangString Example14Desc ${LANG_ENGLISH} `Simple Get function tests.` +LangString Example15Desc ${LANG_ENGLISH} `Simple Delete function tests.` +LangString Example16Desc ${LANG_ENGLISH} `Empty/missing value keys tests.` + +!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN + !insertmacro MUI_DESCRIPTION_TEXT ${EXAMPLE1} $(Example1Desc) + !insertmacro MUI_DESCRIPTION_TEXT ${EXAMPLE1B} $(Example1BDesc) + !insertmacro MUI_DESCRIPTION_TEXT ${EXAMPLE1C} $(Example1CDesc) + !insertmacro MUI_DESCRIPTION_TEXT ${EXAMPLE1D} $(Example1DDesc) + !insertmacro MUI_DESCRIPTION_TEXT ${EXAMPLE1E} $(Example1EDesc) + !insertmacro MUI_DESCRIPTION_TEXT ${EXAMPLE2} $(Example2Desc) + !insertmacro MUI_DESCRIPTION_TEXT ${EXAMPLE3} $(Example3Desc) + !insertmacro MUI_DESCRIPTION_TEXT ${EXAMPLE4} $(Example4Desc) + !insertmacro MUI_DESCRIPTION_TEXT ${EXAMPLE5} $(Example5Desc) + !insertmacro MUI_DESCRIPTION_TEXT ${EXAMPLE5B} $(Example5BDesc) + !insertmacro MUI_DESCRIPTION_TEXT ${EXAMPLE6} $(Example6Desc) + !insertmacro MUI_DESCRIPTION_TEXT ${EXAMPLE7} $(Example7Desc) + !insertmacro MUI_DESCRIPTION_TEXT ${EXAMPLE8} $(Example8Desc) + !insertmacro MUI_DESCRIPTION_TEXT ${EXAMPLE9} $(Example9Desc) + !insertmacro MUI_DESCRIPTION_TEXT ${EXAMPLE10} $(Example10Desc) + !insertmacro MUI_DESCRIPTION_TEXT ${EXAMPLE11} $(Example11Desc) + !insertmacro MUI_DESCRIPTION_TEXT ${EXAMPLE12} $(Example12Desc) + !insertmacro MUI_DESCRIPTION_TEXT ${EXAMPLE13} $(Example13Desc) + !insertmacro MUI_DESCRIPTION_TEXT ${EXAMPLE14} $(Example14Desc) + !insertmacro MUI_DESCRIPTION_TEXT ${EXAMPLE15} $(Example15Desc) + !insertmacro MUI_DESCRIPTION_TEXT ${EXAMPLE16} $(Example16Desc) +!insertmacro MUI_FUNCTION_DESCRIPTION_END \ No newline at end of file diff --git a/agent/installer/ns_json/Examples/nsJSON/HttpWebRequest.nsi b/agent/installer/ns_json/Examples/nsJSON/HttpWebRequest.nsi new file mode 100644 index 00000000000..ada981cac7c --- /dev/null +++ b/agent/installer/ns_json/Examples/nsJSON/HttpWebRequest.nsi @@ -0,0 +1,127 @@ +!include MUI2.nsh + +!define HttpWebRequestURL `http://www.afrowsoft.co.uk/test/HttpWebRequest.php` + +Name `nsJSON plug-in` +OutFile nsJSON_HttpWebRequest.exe +RequestExecutionLevel user +ShowInstDetails show + +!define MUI_COMPONENTSPAGE_SMALLDESC +!insertmacro MUI_PAGE_COMPONENTS +!insertmacro MUI_PAGE_INSTFILES + +!insertmacro MUI_LANGUAGE English + +Section + + CreateDirectory $EXEDIR\Output + +SectionEnd + +Section /o `POST` DATAPOST + + StrCpy $R0 `{ "Name": "Jonathan Doe", "Age": 23, "Formula": "a + b == 13%!", "ViewTimes": [ "10:00", "13:43", "21:19", "03:10" ] }` + + nsJSON::Set /tree HttpWebRequest /value `{ "Url": "${HttpWebRequestURL}", "Verb": "POST", "Agent": "Mozilla/5.0 (Windows NT 10.0; rv:10.0) Gecko/20100101 Firefox/10.0" }` + DetailPrint `Send: $R0` + DetailPrint `Send to: ${HttpWebRequestURL}` + nsJSON::Set /tree HttpWebRequest Data /value $R0 + + nsJSON::Set /tree HttpWebRequest Params /value `{ "a": "string", "b": true, "c": 2 }` + + DetailPrint `Generate: $EXEDIR\Output\HttpWebRequest.json from HttpWebRequest` + nsJSON::Serialize /tree HttpWebRequest /format /file $EXEDIR\Output\HttpWebRequest.json + + DetailPrint `Download: ${HttpWebRequestURL}` + nsJSON::Set /tree HttpWebResponse /http HttpWebRequest + + DetailPrint `Generate: $EXEDIR\Output\HttpWebResponse.json from HttpWebResponse` + nsJSON::Serialize /tree HttpWebResponse /format /file $EXEDIR\Output\HttpWebResponse.json + +SectionEnd + +Section /o `Async POST` DATAPOSTASYNC + + StrCpy $R0 `{ "Name": "Jonathan Doe", "Age": 23, "Formula": "a + b == 13%!", "ViewTimes": [ "10:00", "13:43", "21:19", "03:10" ] }` + + nsJSON::Set /tree HttpWebRequest /value `{ "Url": "${HttpWebRequestURL}", "Verb": "POST", "Async": true }` + DetailPrint `Send: $R0` + DetailPrint `Send to: ${HttpWebRequestURL}` + nsJSON::Set /tree HttpWebRequest Data /value $R0 + + nsJSON::Set /tree HttpWebRequest Params /value `{ "a": "string", "b": true, "c": 2 }` + + DetailPrint `Generate: $EXEDIR\Output\HttpWebRequest.json from HttpWebRequest` + nsJSON::Serialize /tree HttpWebRequest /format /file $EXEDIR\Output\HttpWebRequest.json + + DetailPrint `Download: ${HttpWebRequestURL}` + nsJSON::Set /tree AsyncHttpWebResponse /http HttpWebRequest + + ; Wait until done. + ${Do} + Sleep 1000 + nsJSON::Wait HttpWebRequest /timeout 0 + Pop $R0 + ${If} $R0 != wait + ${Break} + ${EndIf} + DetailPrint `Waiting...` + ${Loop} + + DetailPrint `Finished...` + + DetailPrint `Generate: $EXEDIR\Output\AsyncHttpWebResponse.json from AsyncHttpWebResponse` + nsJSON::Serialize /tree AsyncHttpWebResponse /format /file $EXEDIR\Output\AsyncHttpWebResponse.json + +SectionEnd + +Section /o `Raw POST` RAWDATAPOST + + StrCpy $R0 `Name=Jonathan+Doe&Age=23&Formula=a+%2B+b+%3D%3D+13%25%21&ViewTimes[]=10%3A00&ViewTimes[]=13%3A43&ViewTimes[]=21%3A19&ViewTimes[]=03%3A10` + + nsJSON::Set /tree HttpWebRequest /value `{ "Url": "${HttpWebRequestURL}", "Verb": "POST", "DataType": "Raw" }` + DetailPrint `Send: $R0` + DetailPrint `Send to: ${HttpWebRequestURL}` + nsJSON::Set /tree HttpWebRequest Data /value `"$R0"` + + DetailPrint `Generate: $EXEDIR\Output\HttpWebRequest_Raw.json from HttpWebRequest` + nsJSON::Serialize /tree HttpWebRequest /format /file $EXEDIR\Output\HttpWebRequest_Raw.json + + DetailPrint `Download: ${HttpWebRequestURL}` + nsJSON::Set /tree HttpWebResponse /http HttpWebRequest + + DetailPrint `Generate: $EXEDIR\Output\HttpWebResponse_Raw.json from HttpWebResponse` + nsJSON::Serialize /tree HttpWebResponse /format /file $EXEDIR\Output\HttpWebResponse_Raw.json + +SectionEnd + +Section /o `JSON POST` JSONPOST + + nsJSON::Set /tree HttpWebRequest /value `{ "Url": "${HttpWebRequestURL}", "Verb": "POST", "DataType": "JSON" }` + DetailPrint `Send: $EXEDIR\Input\Example1.json` + DetailPrint `Send to: ${HttpWebRequestURL}` + nsJSON::Set /tree HttpWebRequest Data /file $EXEDIR\Input\Example1.json + + DetailPrint `Generate: $EXEDIR\Output\HttpWebRequest_JSON.json from HttpWebRequest` + nsJSON::Serialize /tree HttpWebRequest /format /file $EXEDIR\Output\HttpWebRequest_JSON.json + + DetailPrint `Download: ${HttpWebRequestURL}` + nsJSON::Set /tree HttpWebResponse /http HttpWebRequest + + DetailPrint `Generate: $EXEDIR\Output\HttpWebResponse_JSON.json from HttpWebResponse` + nsJSON::Serialize /tree HttpWebResponse /format /file $EXEDIR\Output\HttpWebResponse_JSON.json + +SectionEnd + +LangString DataPOSTDesc ${LANG_ENGLISH} `Sends POST data and parses the JSON response` +LangString DataPOSTAsyncDesc ${LANG_ENGLISH} `Asynchronously sends POST data and parses the JSON response` +LangString RawDataPOSTDesc ${LANG_ENGLISH} `Sends raw POST data and parses the JSON response` +LangString JSONPOSTDesc ${LANG_ENGLISH} `Sends Example1.json and parses the JSON response` + +!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN + !insertmacro MUI_DESCRIPTION_TEXT ${DATAPOST} $(DataPOSTDesc) + !insertmacro MUI_DESCRIPTION_TEXT ${DATAPOSTASYNC} $(DataPOSTAsyncDesc) + !insertmacro MUI_DESCRIPTION_TEXT ${RAWDATAPOST} $(RawDataPOSTDesc) + !insertmacro MUI_DESCRIPTION_TEXT ${JSONPOST} $(JSONPOSTDesc) +!insertmacro MUI_FUNCTION_DESCRIPTION_END \ No newline at end of file diff --git a/agent/installer/ns_json/Examples/nsJSON/Input/Example1.json b/agent/installer/ns_json/Examples/nsJSON/Input/Example1.json new file mode 100644 index 00000000000..282e5594159 --- /dev/null +++ b/agent/installer/ns_json/Examples/nsJSON/Input/Example1.json @@ -0,0 +1,22 @@ +{ + "glossary": { + "title": "example glossary", + "GlossDiv": { + "title": "S", + "GlossList": { + "GlossEntry": { + "ID": "SGML", + "SortAs": "SGML", + "GlossTerm": "Standard Generalized Markup Language", + "Acronym": "SGML", + "Abbrev": "ISO 8879:1986", + "GlossDef": { + "para": "A meta-markup language, used to create markup languages such as DocBook.", + "GlossSeeAlso": ["GML", "XML"] + }, + "GlossSee": "markup" + } + } + } + } +} \ No newline at end of file diff --git a/agent/installer/ns_json/Examples/nsJSON/Input/Example1_Unicode.json b/agent/installer/ns_json/Examples/nsJSON/Input/Example1_Unicode.json new file mode 100644 index 00000000000..9b465ef2254 Binary files /dev/null and b/agent/installer/ns_json/Examples/nsJSON/Input/Example1_Unicode.json differ diff --git a/agent/installer/ns_json/Examples/nsJSON/Input/Example1_Unicode_UTF16BE.json b/agent/installer/ns_json/Examples/nsJSON/Input/Example1_Unicode_UTF16BE.json new file mode 100644 index 00000000000..c2a2ad34d1e Binary files /dev/null and b/agent/installer/ns_json/Examples/nsJSON/Input/Example1_Unicode_UTF16BE.json differ diff --git a/agent/installer/ns_json/Examples/nsJSON/Input/Example1_Unicode_UTF16LE.json b/agent/installer/ns_json/Examples/nsJSON/Input/Example1_Unicode_UTF16LE.json new file mode 100644 index 00000000000..023c0dbcaab Binary files /dev/null and b/agent/installer/ns_json/Examples/nsJSON/Input/Example1_Unicode_UTF16LE.json differ diff --git a/agent/installer/ns_json/Examples/nsJSON/Input/Example1_Unicode_UTF8.json b/agent/installer/ns_json/Examples/nsJSON/Input/Example1_Unicode_UTF8.json new file mode 100644 index 00000000000..66cb100521c --- /dev/null +++ b/agent/installer/ns_json/Examples/nsJSON/Input/Example1_Unicode_UTF8.json @@ -0,0 +1,22 @@ +{ + "glossary": { + "title": "example glossary", + "GlossDiv": { + "title": "S", + "GlossList": { + "GlossEntry": { + "ID": "SGML", + "SortAs": "SGML", + "GlossTerm": "Standard Generalized Markup Language", + "Acronym": "SGML", + "Abbrev": "ISO 8879:1986", + "GlossDef": { + "para": "A meta-markup language, used to create markup languages such as DocBook.", + "GlossSeeAlso": ["GML", "XML"] + }, + "GlossSee": "markup" + } + } + } + } +} \ No newline at end of file diff --git a/agent/installer/ns_json/Examples/nsJSON/Input/Example2.json b/agent/installer/ns_json/Examples/nsJSON/Input/Example2.json new file mode 100644 index 00000000000..bae9fc920bd --- /dev/null +++ b/agent/installer/ns_json/Examples/nsJSON/Input/Example2.json @@ -0,0 +1,14 @@ +{ + "menu": { + "id": "file", + "value": "File", + "popup": { + "menuitem": [ + {"value": "New", "onclick": "CreateNewDoc()"}, + {"value": "Open", "onclick": "OpenDoc()"}, + {"value": "Close", "onclick": "CloseDoc()"}, + {"value": "Import", "onclick": "Import('somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_somereallylongvalue_')"} + ] + } + } +} \ No newline at end of file diff --git a/agent/installer/ns_json/Examples/nsJSON/Input/Example3.json b/agent/installer/ns_json/Examples/nsJSON/Input/Example3.json new file mode 100644 index 00000000000..8cd8e5d88af --- /dev/null +++ b/agent/installer/ns_json/Examples/nsJSON/Input/Example3.json @@ -0,0 +1,28 @@ +{ + "widget": { + "debug": "on", + "window": { + "title": "Sample Konfabulator Widget", + "name": "main_window", + "width": 500, + "height": 500 + }, + "image": { + "src": "Images/Sun.png", + "name": "sun1", + "hOffset": 250, + "vOffset": 250, + "alignment": "center" + }, + "text": { + "data": "Click Here", + "size": 36, + "style": "bold", + "name": "text1", + "hOffset": 250, + "vOffset": 100, + "alignment": "center", + "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" + } + } +} \ No newline at end of file diff --git a/agent/installer/ns_json/Examples/nsJSON/Input/Example4.json b/agent/installer/ns_json/Examples/nsJSON/Input/Example4.json new file mode 100644 index 00000000000..31879b7b719 --- /dev/null +++ b/agent/installer/ns_json/Examples/nsJSON/Input/Example4.json @@ -0,0 +1,99 @@ +{ + "web-app": { + "servlet": [ + { + "servlet-name": "cofaxCDS", + "servlet-class": "org.cofax.cds.CDSServlet", + "init-param": { + "configGlossary:installationAt": "Philadelphia, PA", + "configGlossary:adminEmail": "ksm@pobox.com", + "configGlossary:poweredBy": "Cofax", + "configGlossary:poweredByIcon": "/images/cofax.gif", + "configGlossary:staticPath": "/content/static", + "templateProcessorClass": "org.cofax.WysiwygTemplate", + "templateLoaderClass": "org.cofax.FilesTemplateLoader", + "templatePath": "templates", + "templateOverridePath": "", + "defaultListTemplate": "listTemplate.htm", + "defaultFileTemplate": "articleTemplate.htm", + "useJSP": false, + "jspListTemplate": "listTemplate.jsp", + "jspFileTemplate": "articleTemplate.jsp", + "cachePackageTagsTrack": 200, + "cachePackageTagsStore": 200, + "cachePackageTagsRefresh": 60, + "cacheTemplatesTrack": 100, + "cacheTemplatesStore": 50, + "cacheTemplatesRefresh": 15, + "cachePagesTrack": 200, + "cachePagesStore": 100, + "cachePagesRefresh": 10, + "cachePagesDirtyRead": 10, + "searchEngineListTemplate": "forSearchEnginesList.htm", + "searchEngineFileTemplate": "forSearchEngines.htm", + "searchEngineRobotsDb": "WEB-INF/robots.db", + "useDataStore": true, + "dataStoreClass": "org.cofax.SqlDataStore", + "redirectionClass": "org.cofax.SqlRedirection", + "dataStoreName": "cofax", + "dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver", + "dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon", + "dataStoreUser": "sa", + "dataStorePassword": "dataStoreTestQuery", + "dataStoreTestQuery": "SET NOCOUNT ON;select test='test';", + "dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log", + "dataStoreInitConns": 10, + "dataStoreMaxConns": 100, + "dataStoreConnUsageLimit": 100, + "dataStoreLogLevel": "debug", + "maxUrlLength": 500 + } + }, + { + "servlet-name": "cofaxEmail", + "servlet-class": "org.cofax.cds.EmailServlet", + "init-param": { + "mailHost": "mail1", + "mailHostOverride": "mail2" + } + }, + { + "servlet-name": "cofaxAdmin", + "servlet-class": "org.cofax.cds.AdminServlet" + }, + { + "servlet-name": "fileServlet", + "servlet-class": "org.cofax.cds.FileServlet" + }, + { + "servlet-name": "cofaxTools", + "servlet-class": "org.cofax.cms.CofaxToolsServlet", + "init-param": { + "templatePath": "toolstemplates/", + "log": 1, + "logLocation": "/usr/local/tomcat/logs/CofaxTools.log", + "logMaxSize": "", + "dataLog": 1, + "dataLogLocation": "/usr/local/tomcat/logs/dataLog.log", + "dataLogMaxSize": "", + "removePageCache": "/content/admin/remove?cache=pages&id=", + "removeTemplateCache": "/content/admin/remove?cache=templates&id=", + "fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder", + "lookInContext": 1, + "adminGroupID": 4, + "betaServer": true + } + } ], + "servlet-mapping": { + "cofaxCDS": "/", + "cofaxEmail": "/cofaxutil/aemail/*", + "cofaxAdmin": "/admin/*", + "fileServlet": "/static/*", + "cofaxTools": "/tools/*" + }, + "taglib": { + "taglib-uri": "cofax.tld", + "taglib-location": "/WEB-INF/tlds/cofax.tld" + } + } +} \ No newline at end of file diff --git a/agent/installer/ns_json/Examples/nsJSON/Input/Example5.json b/agent/installer/ns_json/Examples/nsJSON/Input/Example5.json new file mode 100644 index 00000000000..e9017f604c6 --- /dev/null +++ b/agent/installer/ns_json/Examples/nsJSON/Input/Example5.json @@ -0,0 +1,29 @@ +{ + "menu": { + "header": "SVG Viewer", + "items": [ + {"id": "Open"}, + {"id": "OpenNew", "label": "Open New"}, + null, + {"id": "ZoomIn", "label": "Zoom In"}, + {"id": "ZoomOut", "label": "Zoom Out"}, + {"id": "OriginalView", "label": "Original View"}, + null, + {"id": "Quality"}, + {"id": "Pause"}, + {"id": "Mute"}, + null, + {"id": "Find", "label": "Find..."}, + {"id": "FindAgain", "label": "Find Again"}, + {"id": "Copy"}, + {"id": "CopyAgain", "label": "Copy Again"}, + {"id": "CopySVG", "label": "Copy SVG"}, + {"id": "ViewSVG", "label": "View SVG"}, + {"id": "ViewSource", "label": "View Source"}, + {"id": "SaveAs", "label": "Save As"}, + null, + {"id": "Help"}, + {"id": "About", "label": "About Adobe CVG Viewer..."} + ] + } +} \ No newline at end of file diff --git a/agent/installer/ns_json/Examples/nsJSON/Input/Preferences.json b/agent/installer/ns_json/Examples/nsJSON/Input/Preferences.json new file mode 100644 index 00000000000..e48e8484ef2 --- /dev/null +++ b/agent/installer/ns_json/Examples/nsJSON/Input/Preferences.json @@ -0,0 +1,992 @@ +{ + "apps": { + "shortcuts_have_been_created": true + }, + "browser": { + "last_known_google_url": "https://www.google.co.uk/", + "last_prompted_google_url": "https://www.google.co.uk/", + "window_placement": { + "bottom": 1087, + "left": 682, + "maximized": false, + "right": 1627, + "top": 67, + "work_area_bottom": 1040, + "work_area_left": 0, + "work_area_right": 1920, + "work_area_top": 0 + } + }, + "countryid_at_install": 21843, + "default_apps_install_state": 3, + "default_search_provider": { + "alternate_urls": [ "{google:baseURL}#q={searchTerms}", "{google:baseURL}search#q={searchTerms}", "{google:baseURL}webhp#q={searchTerms}" ], + "enabled": true, + "encodings": "UTF-8", + "icon_url": "http://www.google.com/favicon.ico", + "id": "2", + "image_url": "{google:baseURL}searchbyimage/upload", + "image_url_post_params": "encoded_image={google:imageThumbnail},image_url={google:imageURL},sbisrc={google:imageSearchSource},original_width={google:imageOriginalWidth},original_height={google:imageOriginalHeight}", + "instant_url": "{google:baseURL}webhp?sourceid=chrome-instant&{google:RLZ}{google:forceInstantResults}{google:instantExtendedEnabledParameter}{google:ntpIsThemedParameter}{google:omniboxStartMarginParameter}ie={inputEncoding}", + "instant_url_post_params": "", + "keyword": "google.co.uk", + "name": "Google", + "new_tab_url": "{google:baseURL}_/chrome/newtab?{google:RLZ}{google:instantExtendedEnabledParameter}{google:ntpIsThemedParameter}ie={inputEncoding}", + "prepopulate_id": "1", + "search_terms_replacement_key": "espv", + "search_url": "{google:baseURL}search?q={searchTerms}&{google:RLZ}{google:originalQueryForSuggestion}{google:assistedQueryStats}{google:searchFieldtrialParameter}{google:bookmarkBarPinned}{google:searchClient}{google:sourceId}{google:instantExtendedEnabledParameter}{google:omniboxStartMarginParameter}ie={inputEncoding}", + "search_url_post_params": "", + "suggest_url": "{google:baseSuggestURL}search?{google:searchFieldtrialParameter}client={google:suggestClient}&gs_ri={google:suggestRid}&xssi=t&q={searchTerms}&{google:cursorPosition}{google:currentPageUrl}{google:pageClassification}sugkey={google:suggestAPIKeyParameter}", + "suggest_url_post_params": "" + }, + "extensions": { + "alerts": { + "initialized": true + }, + "autoupdate": { + "next_check": "13040578803125671", + "test": "E:\\", + "test2": "E:\\\"" + }, + "chrome_url_overrides": { + "bookmarks": [ "chrome-extension://eemcgdkfndhakfknompkggombfjjjeno/main.html" ] + }, + "known_disabled": [ ], + "last_chrome_version": "33.0.1750.154", + "settings": { + "ahfgeienlihckogmohjhadlkjgocpleb": { + "active_permissions": { + "api": [ "management", "webstorePrivate" ], + "manifest_permissions": [ ] + }, + "app_launcher_ordinal": "t", + "content_settings": [ ], + "creation_flags": 1, + "events": [ ], + "from_bookmark": false, + "from_webstore": false, + "incognito_content_settings": [ ], + "incognito_preferences": { + + }, + "install_time": "13040559080062671", + "location": 5, + "manifest": { + "app": { + "launch": { + "web_url": "https://chrome.google.com/webstore" + }, + "urls": [ "https://chrome.google.com/webstore" ] + }, + "description": "Chrome Web Store", + "icons": { + "128": "webstore_icon_128.png", + "16": "webstore_icon_16.png" + }, + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCtl3tO0osjuzRsf6xtD2SKxPlTfuoy7AWoObysitBPvH5fE1NaAA1/2JkPWkVDhdLBWLaIBPYeXbzlHp3y4Vv/4XG+aN5qFE3z+1RU/NqkzVYHtIpVScf3DjTYtKVL66mzVGijSoAIwbFCC3LpGdaoe6Q1rSRDp76wR6jjFzsYwQIDAQAB", + "name": "Store", + "permissions": [ "webstorePrivate", "management" ], + "version": "0.2" + }, + "page_ordinal": "n", + "path": "C:\\Program Files (x86)\\Google\\Chrome\\Application\\33.0.1750.154\\resources\\web_store", + "preferences": { + + }, + "regular_only_preferences": { + + }, + "was_installed_by_default": false + }, + "aohghmighlieiainnegkcijnfilokake": { + "ack_external": true, + "active_permissions": { + "api": [ ], + "manifest_permissions": [ ] + }, + "app_launcher_ordinal": "w", + "content_settings": [ ], + "creation_flags": 137, + "events": [ ], + "from_bookmark": false, + "from_webstore": true, + "granted_permissions": { + "api": [ ], + "manifest_permissions": [ ] + }, + "incognito_content_settings": [ ], + "incognito_preferences": { + + }, + "initial_keybindings_set": true, + "install_time": "13040559089376747", + "lastpingday": "13040550028882747", + "location": 1, + "manifest": { + "api_console_project_id": "619683526622", + "app": { + "launch": { + "local_path": "main.html" + } + }, + "container": "GOOGLE_DRIVE", + "current_locale": "en_GB", + "default_locale": "en_US", + "description": "Create and edit documents", + "icons": { + "128": "icon_128.png", + "16": "icon_16.png" + }, + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJhLK6fk/BWTEvJhywpk7jDe4A2r0bGXGOLZW4/AdBp3IiD9o9nx4YjLAtv0tIPxi7MvFd/GUUbQBwHT5wQWONJj1z/0Rc2qBkiJA0yqXh42p0snuA8dCfdlhOLsp7/XTMEwAVasjV5hC4awl78eKfJYlZ+8fM/UldLWJ/51iBQwIDAQAB", + "manifest_version": 2, + "name": "Google Docs", + "offline_enabled": true, + "update_url": "http://clients2.google.com/service/update2/crx", + "version": "0.5" + }, + "page_ordinal": "n", + "path": "aohghmighlieiainnegkcijnfilokake\\0.5_0", + "preferences": { + + }, + "regular_only_preferences": { + + }, + "state": 1, + "was_installed_by_default": true + }, + "apdfllckaahabafndbhieahigkjlhalf": { + "ack_external": true, + "active_permissions": { + "api": [ "background", "clipboardRead", "clipboardWrite", "notifications", "unlimitedStorage" ], + "manifest_permissions": [ ] + }, + "app_launcher_ordinal": "yn", + "content_settings": [ ], + "creation_flags": 137, + "events": [ ], + "from_bookmark": false, + "from_webstore": true, + "granted_permissions": { + "api": [ "background", "clipboardRead", "clipboardWrite", "notifications", "unlimitedStorage" ], + "manifest_permissions": [ ] + }, + "incognito_content_settings": [ ], + "incognito_preferences": { + + }, + "install_time": "13040559088240747", + "lastpingday": "13040550028882747", + "location": 1, + "manifest": { + "app": { + "launch": { + "web_url": "https://drive.google.com/?usp=chrome_app" + }, + "urls": [ "http://docs.google.com/", "http://drive.google.com/", "https://docs.google.com/", "https://drive.google.com/" ] + }, + "background": { + "allow_js_access": false + }, + "current_locale": "en_GB", + "default_locale": "en_US", + "description": "Google Drive: create, share and keep all your stuff in one place.", + "icons": { + "128": "128.png" + }, + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDIl5KlKwL2TSkntkpY3naLLz5jsN0YwjhZyObcTOK6Nda4Ie21KRqZau9lx5SHcLh7pE2/S9OiArb+na2dn7YK5EvH+aRXS1ec3uxVlBhqLdnleVgwgwlg5fH95I52IeHcoeK6pR4hW/Nv39GNlI/Uqk6O6GBCCsAxYrdxww9BiQIDAQAB", + "manifest_version": 2, + "name": "Google Drive", + "offline_enabled": true, + "options_page": "https://drive.google.com/settings", + "permissions": [ "background", "clipboardRead", "clipboardWrite", "notifications", "unlimitedStorage" ], + "update_url": "http://clients2.google.com/service/update2/crx", + "version": "6.3" + }, + "page_ordinal": "n", + "path": "apdfllckaahabafndbhieahigkjlhalf\\6.3_0", + "preferences": { + + }, + "regular_only_preferences": { + + }, + "state": 1, + "was_installed_by_default": true + }, + "blpcfgokakmgnkcojhhkbfbldkacnbeo": { + "ack_external": true, + "active_permissions": { + "api": [ ], + "manifest_permissions": [ ] + }, + "app_launcher_ordinal": "x", + "content_settings": [ ], + "creation_flags": 153, + "events": [ ], + "from_bookmark": true, + "from_webstore": true, + "granted_permissions": { + "api": [ ], + "manifest_permissions": [ ] + }, + "incognito_content_settings": [ ], + "incognito_preferences": { + + }, + "install_time": "13040559088955747", + "lastpingday": "13040550028882747", + "location": 1, + "manifest": { + "app": { + "launch": { + "container": "tab", + "web_url": "http://www.youtube.com/?feature=ytca" + }, + "web_content": { + "enabled": true, + "origin": "http://www.youtube.com" + } + }, + "current_locale": "en_GB", + "default_locale": "en", + "description": "The world's most popular online video community.", + "icons": { + "128": "128.png" + }, + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDC/HotmFlyuz5FaHaIbVBhhL4BwbcUtsfWwzgUMpZt5ZsLB2nW/Y5xwNkkPANYGdVsJkT2GPpRRIKBO5QiJ7jPMa3EZtcZHpkygBlQLSjMhdrAKevpKgIl6YTkwzNvExY6rzVDzeE9zqnIs33eppY4S5QcoALMxuSWlMKqgFQjHQIDAQAB", + "manifest_version": 2, + "name": "YouTube", + "permissions": [ "appNotifications" ], + "update_url": "http://clients2.google.com/service/update2/crx", + "version": "4.2.6" + }, + "page_ordinal": "n", + "path": "blpcfgokakmgnkcojhhkbfbldkacnbeo\\4.2.6_0", + "preferences": { + + }, + "regular_only_preferences": { + + }, + "state": 1, + "was_installed_by_default": true + }, + "coobgpohoikkiipiblmjeljniedjpjpf": { + "ack_external": true, + "active_permissions": { + "api": [ ], + "manifest_permissions": [ ] + }, + "app_launcher_ordinal": "z", + "content_settings": [ ], + "creation_flags": 153, + "events": [ ], + "from_bookmark": true, + "from_webstore": true, + "granted_permissions": { + "api": [ ], + "manifest_permissions": [ ] + }, + "incognito_content_settings": [ ], + "incognito_preferences": { + + }, + "install_time": "13040559087816747", + "lastpingday": "13040550028882747", + "location": 1, + "manifest": { + "app": { + "launch": { + "web_url": "http://www.google.com/webhp?source=search_app" + }, + "urls": [ "*://www.google.com/search", "*://www.google.com/webhp", "*://www.google.com/imgres" ] + }, + "current_locale": "en_GB", + "default_locale": "en", + "description": "The fastest way to search the web.", + "icons": { + "128": "128.png", + "16": "16.png", + "32": "32.png", + "48": "48.png" + }, + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDIiso3Loy5VJHL40shGhUl6it5ZG55XB9q/2EX6aa88jAxwPutbCgy5d9bm1YmBzLfSgpX4xcpgTU08ydWbd7b50fbkLsqWl1mRhxoqnN01kuNfv9Hbz9dWWYd+O4ZfD3L2XZs0wQqo0y6k64n+qeLkUMd1MIhf6MR8Xz1SOA8pwIDAQAB", + "manifest_version": 2, + "name": "Google Search", + "permissions": [ ], + "update_url": "http://clients2.google.com/service/update2/crx", + "version": "0.0.0.20" + }, + "page_ordinal": "n", + "path": "coobgpohoikkiipiblmjeljniedjpjpf\\0.0.0.20_0", + "preferences": { + + }, + "regular_only_preferences": { + + }, + "state": 1, + "was_installed_by_default": true + }, + "eemcgdkfndhakfknompkggombfjjjeno": { + "active_permissions": { + "api": [ "bookmarks", "bookmarkManagerPrivate", "metricsPrivate", "systemPrivate", "tabs" ], + "explicit_host": [ "chrome://favicon/*", "chrome://resources/*" ], + "manifest_permissions": [ ] + }, + "content_settings": [ ], + "creation_flags": 1, + "events": [ ], + "from_bookmark": false, + "from_webstore": false, + "incognito_content_settings": [ ], + "incognito_preferences": { + + }, + "initial_keybindings_set": true, + "install_time": "13040559080062671", + "location": 5, + "manifest": { + "chrome_url_overrides": { + "bookmarks": "main.html" + }, + "content_security_policy": "object-src 'none'; script-src chrome://resources 'self'", + "description": "Bookmark Manager", + "icons": { + + }, + "incognito": "split", + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQcByy+eN9jzazWF/DPn7NW47sW7lgmpk6eKc0BQM18q8hvEM3zNm2n7HkJv/R6fU+X5mtqkDuKvq5skF6qqUF4oEyaleWDFhd1xFwV7JV+/DU7bZ00w2+6gzqsabkerFpoP33ZRIw7OviJenP0c0uWqDWF8EGSyMhB3txqhOtiQIDAQAB", + "manifest_version": 2, + "name": "Bookmark Manager", + "permissions": [ "bookmarks", "bookmarkManagerPrivate", "metricsPrivate", "systemPrivate", "tabs", "chrome://favicon/", "chrome://resources/" ], + "version": "0.1" + }, + "path": "C:\\Program Files (x86)\\Google\\Chrome\\Application\\33.0.1750.154\\resources\\bookmark_manager", + "preferences": { + + }, + "regular_only_preferences": { + + }, + "was_installed_by_default": false + }, + "ennkphjdgehloodpbhlhldgbnhmacadg": { + "active_permissions": { + "api": [ "app.currentWindowInternal", "app.runtime", "app.window" ], + "explicit_host": [ "chrome://settings-frame/*" ], + "manifest_permissions": [ ] + }, + "content_settings": [ ], + "creation_flags": 1, + "events": [ "app.runtime.onLaunched" ], + "from_bookmark": false, + "from_webstore": false, + "incognito_content_settings": [ ], + "incognito_preferences": { + + }, + "initial_keybindings_set": true, + "install_time": "13040559080062671", + "location": 5, + "manifest": { + "app": { + "background": { + "scripts": [ "settings_app.js" ] + } + }, + "description": "Settings", + "display_in_launcher": false, + "icons": { + "128": "settings_app_icon_128.png", + "16": "settings_app_icon_16.png", + "32": "settings_app_icon_32.png", + "48": "settings_app_icon_48.png" + }, + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDoVDPGX6fvKPVVgc+gnkYlGqHuuapgFDyKhsy4z7UzRLO/95zXPv8h8e5EacqbAQJLUbP6DERH5jowyNEYVxq9GJyntJMwP1ejvoz/52hnY3CCGGCmttmKzzpp5zwLuq3iZf8bslwywfflNUYtaCFSDa0TtrBZz0aOPrAAd/AhNwIDAQAB", + "manifest_version": 2, + "name": "Settings", + "permissions": [ "chrome://settings-frame/" ], + "version": "0.2" + }, + "path": "C:\\Program Files (x86)\\Google\\Chrome\\Application\\33.0.1750.154\\resources\\settings_app", + "preferences": { + + }, + "regular_only_preferences": { + + }, + "running": false, + "was_installed_by_default": false + }, + "gfdkimpbcpahaombhbimeihdjnejgicl": { + "active_permissions": { + "api": [ "app.currentWindowInternal", "app.runtime", "app.window", "feedbackPrivate" ], + "explicit_host": [ "chrome://resources/*" ], + "manifest_permissions": [ ] + }, + "content_settings": [ ], + "creation_flags": 1, + "events": [ "feedbackPrivate.onFeedbackRequested" ], + "from_bookmark": false, + "from_webstore": false, + "incognito_content_settings": [ ], + "incognito_preferences": { + + }, + "initial_keybindings_set": true, + "install_time": "13040559080062671", + "location": 5, + "manifest": { + "app": { + "background": { + "scripts": [ "js/event_handler.js" ] + }, + "content_security_policy": "default-src 'none'; script-src 'self' chrome://resources; style-src 'unsafe-inline' *; img-src *; media-src 'self'" + }, + "description": "User feedback extension", + "display_in_launcher": false, + "display_in_new_tab_page": false, + "icons": { + "32": "images/icon32.png", + "64": "images/icon64.png" + }, + "incognito": "split", + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMZElzFX2J1g1nRQ/8S3rg/1CjFyDltWOxQg+9M8aVgNVxbutEWFQz+oQzIP9BB67mJifULgiv12ToFKsae4NpEUR8sPZjiKDIHumc6pUdixOm8SJ5Rs16SMR6+VYxFUjlVW+5CA3IILptmNBxgpfyqoK0qRpBDIhGk1KDEZ4zqQIDAQAB", + "manifest_version": 2, + "name": "Feedback", + "permissions": [ "feedbackPrivate", "chrome://resources/" ], + "version": "1.0" + }, + "path": "C:\\Program Files (x86)\\Google\\Chrome\\Application\\33.0.1750.154\\resources\\feedback", + "preferences": { + + }, + "regular_only_preferences": { + + }, + "running": false, + "was_installed_by_default": false + }, + "mfehgcgbbipciphmccgaenjidiccnmng": { + "active_permissions": { + "api": [ "cloudPrintPrivate" ], + "manifest_permissions": [ ] + }, + "content_settings": [ ], + "creation_flags": 1, + "events": [ ], + "from_bookmark": false, + "from_webstore": false, + "incognito_content_settings": [ ], + "incognito_preferences": { + + }, + "install_time": "13040559080062671", + "location": 5, + "manifest": { + "app": { + "launch": { + "web_url": "https://www.google.com/cloudprint" + }, + "urls": [ "https://www.google.com/cloudprint/enable_chrome_connector" ] + }, + "description": "Cloud Print", + "display_in_launcher": false, + "icons": { + + }, + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDqOhnwk4+HXVfGyaNsAQdU/js1Na56diW08oF1MhZiwzSnJsEaeuMN9od9q9N4ZdK3o1xXOSARrYdE+syV7Dl31nf6qz3A6K+D5NHe6sSB9yvYlIiN37jdWdrfxxE0pRYEVYZNTe3bzq3NkcYJlOdt1UPcpJB+isXpAGUKUvt7EQIDAQAB", + "name": "Cloud Print", + "permissions": [ "cloudPrintPrivate" ], + "version": "0.1" + }, + "path": "C:\\Program Files (x86)\\Google\\Chrome\\Application\\33.0.1750.154\\resources\\cloud_print", + "preferences": { + + }, + "regular_only_preferences": { + + }, + "was_installed_by_default": false + }, + "mgndgikekgjfcpckkfioiadnlibdjbkf": { + "active_permissions": { + "api": [ ], + "manifest_permissions": [ ] + }, + "app_launcher_ordinal": "n", + "content_settings": [ ], + "creation_flags": 1, + "events": [ ], + "from_bookmark": false, + "from_webstore": false, + "incognito_content_settings": [ ], + "incognito_preferences": { + + }, + "install_time": "13040559080062671", + "location": 5, + "manifest": { + "app": { + "launch": { + "web_url": "http://THIS-WILL-BE-REPLACED" + } + }, + "description": "Chrome as an app", + "display_in_launcher": true, + "display_in_new_tab_page": false, + "icons": { + "128": "product_logo_128.png", + "16": "product_logo_16.png" + }, + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDNuYLEQ1QPMcc5HfWI/9jiEf6FdJWqEtgRmIeI7qtjPLBM5oje+Ny2E2mTAhou5qdJiO2CHWdU1DQXY2F7Zu2gZaKZgHLfK4WimHxUT5Xd9/aro/R9PCzjguM1BLusiWYc9xlj1IsZpyiN1hcjU7SCnBhv1feQlv2WSB5KRiXwhQIDAQAB", + "name": "Chrome", + "version": "0.1" + }, + "page_ordinal": "n", + "path": "C:\\Program Files (x86)\\Google\\Chrome\\Application\\33.0.1750.154\\resources\\chrome_app", + "preferences": { + + }, + "regular_only_preferences": { + + }, + "was_installed_by_default": false + }, + "neajdppkdcdipfabeoofebfddakdcjhd": { + "active_permissions": { + "api": [ "systemPrivate", "ttsEngine" ], + "explicit_host": [ "https://www.google.com/*" ], + "manifest_permissions": [ ] + }, + "content_settings": [ ], + "creation_flags": 1, + "events": [ "ttsEngine.onPause", "ttsEngine.onResume", "ttsEngine.onSpeak", "ttsEngine.onStop" ], + "from_bookmark": false, + "from_webstore": false, + "incognito_content_settings": [ ], + "incognito_preferences": { + + }, + "initial_keybindings_set": true, + "install_time": "13040559080062671", + "location": 5, + "manifest": { + "background": { + "persistent": false, + "scripts": [ "tts_extension.js" ] + }, + "description": "Component extension providing speech via the Google network text-to-speech service.", + "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8GSbNUMGygqQTNDMFGIjZNcwXsHLzkNkHjWbuY37PbNdSDZ4VqlVjzbWqODSe+MjELdv5Keb51IdytnoGYXBMyqKmWpUrg+RnKvQ5ibWr4MW9pyIceOIdp9GrzC1WZGgTmZismYR3AjaIpufZ7xDdQQv+XrghPWCkdVqLN+qZDA1HU+DURznkMICiDDSH2sU0egm9UbWfS218bZqzKeQDiC3OnTPlaxcbJtKUuupIm5knjze3Wo9Ae9poTDMzKgchg0VlFCv3uqox+wlD8sjXBoyBCCK9HpImdVAF1a7jpdgiUHpPeV/26oYzM9/grltwNR3bzECQgSpyXp0eyoegwIDAQAB", + "manifest_version": 2, + "name": "Google Network Speech", + "permissions": [ "systemPrivate", "ttsEngine", "https://www.google.com/" ], + "tts_engine": { + "voices": [ { + "event_types": [ "start", "end", "error" ], + "gender": "female", + "lang": "en-US", + "remote": true, + "voice_name": "Google US English" + }, { + "event_types": [ "start", "end", "error" ], + "gender": "male", + "lang": "en-GB", + "remote": true, + "voice_name": "Google UK English Male" + }, { + "event_types": [ "start", "end", "error" ], + "gender": "female", + "lang": "en-GB", + "remote": true, + "voice_name": "Google UK English Female" + }, { + "event_types": [ "start", "end", "error" ], + "gender": "female", + "lang": "es-ES", + "remote": true, + "voice_name": "Google Español" + }, { + "event_types": [ "start", "end", "error" ], + "gender": "female", + "lang": "fr-FR", + "remote": true, + "voice_name": "Google Français" + }, { + "event_types": [ "start", "end", "error" ], + "gender": "female", + "lang": "it-IT", + "remote": true, + "voice_name": "Google Italiano" + }, { + "event_types": [ "start", "end", "error" ], + "gender": "female", + "lang": "de-DE", + "remote": true, + "voice_name": "Google Deutsch" + }, { + "event_types": [ "start", "end", "error" ], + "gender": "female", + "lang": "ja-JP", + "remote": true, + "voice_name": "Google 日本人" + }, { + "event_types": [ "start", "end", "error" ], + "gender": "female", + "lang": "ko-KR", + "remote": true, + "voice_name": "Google 한국ì˜" + }, { + "event_types": [ "start", "end", "error" ], + "gender": "female", + "lang": "zh-CN", + "remote": true, + "voice_name": "Google 中国的" + } ] + }, + "version": "1.0" + }, + "path": "C:\\Program Files (x86)\\Google\\Chrome\\Application\\33.0.1750.154\\resources\\network_speech_synthesis", + "preferences": { + + }, + "regular_only_preferences": { + + }, + "was_installed_by_default": false + }, + "nkeimhogjdpnpccoofpliimaahmaaome": { + "active_permissions": { + "api": [ "alarms", "desktopCapture", "webConnectable", "webrtcAudioPrivate", "webrtcLoggingPrivate", "system.cpu" ], + "manifest_permissions": [ ] + }, + "content_settings": [ ], + "creation_flags": 1, + "events": [ "alarms.onAlarm", "runtime.onStartup" ], + "from_bookmark": false, + "from_webstore": false, + "incognito_content_settings": [ ], + "incognito_preferences": { + + }, + "initial_keybindings_set": true, + "install_time": "13040559080062671", + "location": 5, + "manifest": { + "background": { + "page": "background.html", + "persistent": false + }, + "externally_connectable": { + "matches": [ "https://*.google.com/hangouts*", "*://localhost/*" ] + }, + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDAQt2ZDdPfoSe/JI6ID5bgLHRCnCu9T36aYczmhw/tnv6QZB2I6WnOCMZXJZlRdqWc7w9jo4BWhYS50Vb4weMfh/I0On7VcRwJUgfAxW2cHB+EkmtI1v4v/OU24OqIa1Nmv9uRVeX0GjhQukdLNhAE6ACWooaf5kqKlCeK+1GOkQIDAQAB", + "manifest_version": 2, + "name": "Hangout Services", + "permissions": [ "alarms", "desktopCapture", "system.cpu", "webrtcAudioPrivate", "webrtcLoggingPrivate" ], + "version": "1.0" + }, + "path": "C:\\Program Files (x86)\\Google\\Chrome\\Application\\33.0.1750.154\\resources\\hangout_services", + "preferences": { + + }, + "regular_only_preferences": { + + }, + "was_installed_by_default": false + }, + "nmmhkkegccagdldgiimedpiccmgmieda": { + "ack_external": true, + "active_permissions": { + "api": [ "app.currentWindowInternal", "app.runtime", "app.window", "identity", "webRequestInternal", "webview" ], + "explicit_host": [ "https://checkout.google.com/*", "https://sandbox.google.com/*", "https://www.google.com/*", "https://www.googleapis.com/*" ], + "manifest_permissions": [ ] + }, + "content_settings": [ ], + "creation_flags": 137, + "events": [ "app.runtime.onLaunched" ], + "from_bookmark": false, + "from_webstore": true, + "incognito_content_settings": [ ], + "incognito_preferences": { + + }, + "initial_keybindings_set": true, + "install_time": "13040559086619747", + "lastpingday": "13040550028882747", + "location": 10, + "manifest": { + "app": { + "background": { + "scripts": [ "craw_background.js" ] + } + }, + "current_locale": "en_GB", + "default_locale": "en", + "description": "Google Wallet for digital goods", + "display_in_launcher": false, + "display_in_new_tab_page": false, + "icons": { + "128": "images/icon_128.png", + "16": "images/icon_16.png" + }, + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrKfMnLqViEyokd1wk57FxJtW2XXpGXzIHBzv9vQI/01UsuP0IV5/lj0wx7zJ/xcibUgDeIxobvv9XD+zO1MdjMWuqJFcKuSS4Suqkje6u+pMrTSGOSHq1bmBVh0kpToN8YoJs/P/yrRd7FEtAXTaFTGxQL4C385MeXSjaQfiRiQIDAQAB", + "manifest_version": 2, + "minimum_chrome_version": "29", + "name": "Google Wallet", + "oauth2": { + "auto_approve": true, + "client_id": "203784468217.apps.googleusercontent.com", + "scopes": [ "https://www.googleapis.com/auth/sierra", "https://www.googleapis.com/auth/sierrasandbox", "https://www.googleapis.com/auth/chromewebstore", "https://www.googleapis.com/auth/chromewebstore.readonly" ] + }, + "permissions": [ "identity", "webview", "https://checkout.google.com/", "https://sandbox.google.com/checkout/", "https://www.google.com/", "https://www.googleapis.com/*" ], + "update_url": "https://clients2.google.com/service/update2/crx", + "version": "0.0.6.1" + }, + "path": "nmmhkkegccagdldgiimedpiccmgmieda\\0.0.6.1_0", + "preferences": { + + }, + "regular_only_preferences": { + + }, + "running": false, + "state": 1, + "was_installed_by_default": true + }, + "pjkljhegncpnkpknbcohdijeoejaedia": { + "ack_external": true, + "active_permissions": { + "api": [ "notifications" ], + "manifest_permissions": [ ] + }, + "app_launcher_ordinal": "y", + "content_settings": [ ], + "creation_flags": 137, + "events": [ ], + "from_bookmark": false, + "from_webstore": true, + "granted_permissions": { + "api": [ "notifications" ], + "manifest_permissions": [ ] + }, + "incognito_content_settings": [ ], + "incognito_preferences": { + + }, + "install_time": "13040559088625747", + "lastpingday": "13040550028882747", + "location": 1, + "manifest": { + "app": { + "launch": { + "container": "tab", + "web_url": "https://mail.google.com/mail/ca" + }, + "urls": [ "*://mail.google.com/mail/ca" ] + }, + "current_locale": "en_GB", + "default_locale": "en", + "description": "Fast, searchable email with less spam.", + "icons": { + "128": "128.png" + }, + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCuGglK43iAz3J9BEYK/Mz6ZhloIMMDqQSAaf3vJt4eHbTbSDsu4WdQ9dQDRcKlg8nwQdePBt0C3PSUBtiSNSS37Z3qEGfS7LCju3h6pI1Yr9MQtxw+jUa7kXXIS09VV73pEFUT/F7c6Qe8L5ZxgAcBvXBh1Fie63qb02I9XQ/CQIDAQAB", + "name": "Gmail", + "options_page": "https://mail.google.com/mail/ca/#settings", + "permissions": [ "notifications" ], + "update_url": "http://clients2.google.com/service/update2/crx", + "version": "7" + }, + "page_ordinal": "n", + "path": "pjkljhegncpnkpknbcohdijeoejaedia\\7_1", + "preferences": { + + }, + "regular_only_preferences": { + + }, + "state": 1, + "was_installed_by_default": true + } + } + }, + "google": { + "services": { + "signin": { + "LSID": "", + "SID": "" + } + } + }, + "intl": { + "accept_languages": "en-GB,en-US,en" + }, + "invalidator": { + "client_id": "XAP6G30QHyob9Zo8hpj1aA==" + }, + "media": { + "device_id_salt": "mKmmRGOM8msXbtxkKMl0Hw==" + }, + "net": { + "http_server_properties": { + "servers": { + "accounts.google.com:443": { + "alternate_protocol": { + "port": 443, + "protocol_str": "quic" + }, + "settings": { + "4": 100 + }, + "supports_spdy": true + }, + "accounts.youtube.com:443": { + "settings": { + "4": 100 + }, + "supports_spdy": true + }, + "apis.google.com:443": { + "settings": { + "4": 100 + }, + "supports_spdy": true + }, + "clients2.google.com:443": { + "settings": { + "4": 100 + }, + "supports_spdy": true + }, + "clients2.googleusercontent.com:443": { + "alternate_protocol": { + "port": 443, + "protocol_str": "quic" + }, + "settings": { + "4": 100 + }, + "supports_spdy": true + }, + "developer.android.com:443": { + "settings": { + "4": 100 + }, + "supports_spdy": true + }, + "fonts.googleapis.com:443": { + "alternate_protocol": { + "port": 443, + "protocol_str": "quic" + }, + "settings": { + "4": 100 + }, + "supports_spdy": true + }, + "oauth.googleusercontent.com:443": { + "alternate_protocol": { + "port": 443, + "protocol_str": "quic" + }, + "supports_spdy": false + }, + "s.ytimg.com:443": { + "settings": { + "4": 100 + }, + "supports_spdy": true + }, + "ssl.google-analytics.com:443": { + "alternate_protocol": { + "port": 443, + "protocol_str": "quic" + }, + "settings": { + "4": 100 + }, + "supports_spdy": true + }, + "ssl.gstatic.com:443": { + "alternate_protocol": { + "port": 443, + "protocol_str": "quic" + }, + "settings": { + "4": 100 + }, + "supports_spdy": true + }, + "themes.googleusercontent.com:443": { + "alternate_protocol": { + "port": 443, + "protocol_str": "quic" + }, + "settings": { + "4": 100 + }, + "supports_spdy": true + }, + "tools.google.com:80": { + "alternate_protocol": { + "port": 80, + "protocol_str": "quic" + }, + "supports_spdy": false + }, + "www.google.com:443": { + "alternate_protocol": { + "port": 443, + "protocol_str": "quic" + }, + "settings": { + "4": 100 + }, + "supports_spdy": true + }, + "www.youtube.com:443": { + "settings": { + "4": 100 + }, + "supports_spdy": true + } + }, + "version": 2 + } + }, + "plugins": { + "migrated_to_pepper_flash": true, + "plugins_list": [ ], + "removed_old_component_pepper_flash_settings": true + }, + "profile": { + "avatar_index": 0, + "content_settings": { + "clear_on_exit_migrated": true, + "pattern_pairs": { + + }, + "pref_version": 1 + }, + "created_by_version": "33.0.1750.154", + "exit_type": "Crashed", + "exited_cleanly": true, + "icon_version": 2, + "managed_user_id": "", + "name": "First user" + }, + "session": { + "restore_on_startup_migrated": true, + "startup_urls_migration_time": "13040559080052671" + }, + "sync_promo": { + "startup_count": 1 + }, + "translate_blocked_languages": [ "en" ], + "translate_whitelists": { + + } +} diff --git a/agent/installer/ns_json/Examples/nsJSON/Input/Preferences2.json b/agent/installer/ns_json/Examples/nsJSON/Input/Preferences2.json new file mode 100644 index 00000000000..4e6b50c0a1f --- /dev/null +++ b/agent/installer/ns_json/Examples/nsJSON/Input/Preferences2.json @@ -0,0 +1,988 @@ +{ + "apps": { + "shortcuts_have_been_created": true + }, + "browser": { + "last_known_google_url": "https://www.google.com.ua/", + "last_prompted_google_url": "https://www.google.com.ua/", + "window_placement": { + "bottom": 919, + "left": 10, + "maximized": false, + "right": 1060, + "top": 10, + "work_area_bottom": 929, + "work_area_left": 0, + "work_area_right": 1280, + "work_area_top": 0 + } + }, + "countryid_at_install": 21077, + "default_apps_install_state": 3, + "distribution": { + "make_chrome_default_for_user": true + }, + "dns_prefetching": { + "host_referral_list": [ 2, [ "https://accounts.google.com/", [ "https://accounts.youtube.com/", 1.500430932, "https://fonts.googleapis.com/", 1.500430932, "https://oauth.googleusercontent.com/", 2.2733802, "https://ssl.gstatic.com/", 2.4847851279999995, "https://themes.googleusercontent.com/", 1.7184422639999999 ] ], [ "https://apis.google.com/", [ "https://apis.google.com/", 2.6037003999999997, "https://ssl.gstatic.com/", 2.2733802 ] ], [ "https://www.google.ru/", [ "https://accounts.google.com/", 2.2733802, "https://apis.google.com/", 3.2643407999999994, "https://developer.android.com/", 2.2733802, "https://fonts.googleapis.com/", 2.2733802, "https://ssl.google-analytics.com/", 2.6037003999999997, "https://ssl.gstatic.com/", 2.2733802, "https://themes.googleusercontent.com/", 3.2643407999999994, "https://www.google.com/", 2.2733802, "https://www.google.ru/", 5.576582199999999 ] ] ], + "startup_list": [ 1, "http://tools.google.com/", "https://accounts.google.com/", "https://accounts.youtube.com/", "https://clients2.google.com/", "https://clients2.googleusercontent.com/", "https://developer.android.com/", "https://fonts.googleapis.com/", "https://ssl.gstatic.com/", "https://www.google.com/", "https://www.google.ru/" ] + }, + "extensions": { + "alerts": { + "initialized": true + }, + "autoupdate": { + "next_check": "13039550398202000" + }, + "chrome_url_overrides": { + "bookmarks": [ "chrome-extension://eemcgdkfndhakfknompkggombfjjjeno/main.html" ] + }, + "known_disabled": [ ], + "last_chrome_version": "33.0.1750.154", + "settings": { + "ahfgeienlihckogmohjhadlkjgocpleb": { + "active_permissions": { + "api": [ "management", "webstorePrivate" ], + "manifest_permissions": [ ] + }, + "app_launcher_ordinal": "t", + "content_settings": [ ], + "creation_flags": 1, + "events": [ ], + "from_bookmark": false, + "from_webstore": false, + "incognito_content_settings": [ ], + "incognito_preferences": { + + }, + "install_time": "13039532121147000", + "location": 5, + "manifest": { + "app": { + "launch": { + "web_url": "https://chrome.google.com/webstore" + }, + "urls": [ "https://chrome.google.com/webstore" ] + }, + "description": "Chrome Web Store", + "icons": { + "128": "webstore_icon_128.png", + "16": "webstore_icon_16.png" + }, + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCtl3tO0osjuzRsf6xtD2SKxPlTfuoy7AWoObysitBPvH5fE1NaAA1/2JkPWkVDhdLBWLaIBPYeXbzlHp3y4Vv/4XG+aN5qFE3z+1RU/NqkzVYHtIpVScf3DjTYtKVL66mzVGijSoAIwbFCC3LpGdaoe6Q1rSRDp76wR6jjFzsYwQIDAQAB", + "name": "???????", + "permissions": [ "webstorePrivate", "management" ], + "version": "0.2" + }, + "page_ordinal": "n", + "path": "C:\\Program Files\\Google\\Chrome\\Application\\33.0.1750.154\\resources\\web_store", + "preferences": { + + }, + "regular_only_preferences": { + + }, + "was_installed_by_default": false + }, + "aohghmighlieiainnegkcijnfilokake": { + "ack_external": true, + "active_permissions": { + "api": [ ], + "manifest_permissions": [ ] + }, + "app_launcher_ordinal": "w", + "content_settings": [ ], + "creation_flags": 137, + "events": [ ], + "from_bookmark": false, + "from_webstore": true, + "granted_permissions": { + "api": [ ], + "manifest_permissions": [ ] + }, + "incognito_content_settings": [ ], + "incognito_preferences": { + + }, + "initial_keybindings_set": true, + "install_time": "13039532128470599", + "lastpingday": "13039513199557599", + "location": 1, + "manifest": { + "api_console_project_id": "619683526622", + "app": { + "launch": { + "local_path": "main.html" + } + }, + "container": "GOOGLE_DRIVE", + "current_locale": "ru", + "default_locale": "en_US", + "description": "???????? ? ?????????????? ??????????", + "icons": { + "128": "icon_128.png", + "16": "icon_16.png" + }, + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJhLK6fk/BWTEvJhywpk7jDe4A2r0bGXGOLZW4/AdBp3IiD9o9nx4YjLAtv0tIPxi7MvFd/GUUbQBwHT5wQWONJj1z/0Rc2qBkiJA0yqXh42p0snuA8dCfdlhOLsp7/XTMEwAVasjV5hC4awl78eKfJYlZ+8fM/UldLWJ/51iBQwIDAQAB", + "manifest_version": 2, + "name": "????????? Google", + "offline_enabled": true, + "update_url": "http://clients2.google.com/service/update2/crx", + "version": "0.5" + }, + "page_ordinal": "n", + "path": "aohghmighlieiainnegkcijnfilokake\\0.5_0", + "preferences": { + + }, + "regular_only_preferences": { + + }, + "state": 1, + "was_installed_by_default": true + }, + "apdfllckaahabafndbhieahigkjlhalf": { + "ack_external": true, + "active_permissions": { + "api": [ "background", "clipboardRead", "clipboardWrite", "notifications", "unlimitedStorage" ], + "manifest_permissions": [ ] + }, + "app_launcher_ordinal": "x", + "content_settings": [ ], + "creation_flags": 137, + "events": [ ], + "from_bookmark": false, + "from_webstore": true, + "granted_permissions": { + "api": [ "background", "clipboardRead", "clipboardWrite", "notifications", "unlimitedStorage" ], + "manifest_permissions": [ ] + }, + "incognito_content_settings": [ ], + "incognito_preferences": { + + }, + "install_time": "13039532126820599", + "lastpingday": "13039513199557599", + "location": 1, + "manifest": { + "app": { + "launch": { + "web_url": "https://drive.google.com/?usp=chrome_app" + }, + "urls": [ "http://docs.google.com/", "http://drive.google.com/", "https://docs.google.com/", "https://drive.google.com/" ] + }, + "background": { + "allow_js_access": false + }, + "current_locale": "ru", + "default_locale": "en_US", + "description": "???? Google: ??????????, ?????????? ? ??????? ??? ???? ????? ? ??????? ?????? ???????.", + "icons": { + "128": "128.png" + }, + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDIl5KlKwL2TSkntkpY3naLLz5jsN0YwjhZyObcTOK6Nda4Ie21KRqZau9lx5SHcLh7pE2/S9OiArb+na2dn7YK5EvH+aRXS1ec3uxVlBhqLdnleVgwgwlg5fH95I52IeHcoeK6pR4hW/Nv39GNlI/Uqk6O6GBCCsAxYrdxww9BiQIDAQAB", + "manifest_version": 2, + "name": "???? Google", + "offline_enabled": true, + "options_page": "https://drive.google.com/settings", + "permissions": [ "background", "clipboardRead", "clipboardWrite", "notifications", "unlimitedStorage" ], + "update_url": "http://clients2.google.com/service/update2/crx", + "version": "6.3" + }, + "page_ordinal": "n", + "path": "apdfllckaahabafndbhieahigkjlhalf\\6.3_0", + "preferences": { + + }, + "regular_only_preferences": { + + }, + "state": 1, + "was_installed_by_default": true + }, + "blpcfgokakmgnkcojhhkbfbldkacnbeo": { + "ack_external": true, + "active_permissions": { + "api": [ ], + "manifest_permissions": [ ] + }, + "app_launcher_ordinal": "yn", + "content_settings": [ ], + "creation_flags": 153, + "events": [ ], + "from_bookmark": true, + "from_webstore": true, + "granted_permissions": { + "api": [ ], + "manifest_permissions": [ ] + }, + "incognito_content_settings": [ ], + "incognito_preferences": { + + }, + "install_time": "13039532126409599", + "lastpingday": "13039513199557599", + "location": 1, + "manifest": { + "app": { + "launch": { + "container": "tab", + "web_url": "http://www.youtube.com/?feature=ytca" + }, + "web_content": { + "enabled": true, + "origin": "http://www.youtube.com" + } + }, + "current_locale": "ru", + "default_locale": "en", + "description": "????? ?????????? ? ???? ???????????????.", + "icons": { + "128": "128.png" + }, + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDC/HotmFlyuz5FaHaIbVBhhL4BwbcUtsfWwzgUMpZt5ZsLB2nW/Y5xwNkkPANYGdVsJkT2GPpRRIKBO5QiJ7jPMa3EZtcZHpkygBlQLSjMhdrAKevpKgIl6YTkwzNvExY6rzVDzeE9zqnIs33eppY4S5QcoALMxuSWlMKqgFQjHQIDAQAB", + "manifest_version": 2, + "name": "YouTube", + "permissions": [ "appNotifications" ], + "update_url": "http://clients2.google.com/service/update2/crx", + "version": "4.2.6" + }, + "page_ordinal": "n", + "path": "blpcfgokakmgnkcojhhkbfbldkacnbeo\\4.2.6_0", + "preferences": { + + }, + "regular_only_preferences": { + + }, + "state": 1, + "was_installed_by_default": true + }, + "coobgpohoikkiipiblmjeljniedjpjpf": { + "ack_external": true, + "active_permissions": { + "api": [ ], + "manifest_permissions": [ ] + }, + "app_launcher_ordinal": "z", + "content_settings": [ ], + "creation_flags": 153, + "events": [ ], + "from_bookmark": true, + "from_webstore": true, + "granted_permissions": { + "api": [ ], + "manifest_permissions": [ ] + }, + "incognito_content_settings": [ ], + "incognito_preferences": { + + }, + "install_time": "13039532127382599", + "lastpingday": "13039513199557599", + "location": 1, + "manifest": { + "app": { + "launch": { + "web_url": "http://www.google.com/webhp?source=search_app" + }, + "urls": [ "*://www.google.com/search", "*://www.google.com/webhp", "*://www.google.com/imgres" ] + }, + "current_locale": "ru", + "default_locale": "en", + "description": "????? ??????? ????? ? ?????????.", + "icons": { + "128": "128.png", + "16": "16.png", + "32": "32.png", + "48": "48.png" + }, + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDIiso3Loy5VJHL40shGhUl6it5ZG55XB9q/2EX6aa88jAxwPutbCgy5d9bm1YmBzLfSgpX4xcpgTU08ydWbd7b50fbkLsqWl1mRhxoqnN01kuNfv9Hbz9dWWYd+O4ZfD3L2XZs0wQqo0y6k64n+qeLkUMd1MIhf6MR8Xz1SOA8pwIDAQAB", + "manifest_version": 2, + "name": "????? Google", + "permissions": [ ], + "update_url": "http://clients2.google.com/service/update2/crx", + "version": "0.0.0.20" + }, + "page_ordinal": "n", + "path": "coobgpohoikkiipiblmjeljniedjpjpf\\0.0.0.20_0", + "preferences": { + + }, + "regular_only_preferences": { + + }, + "state": 1, + "was_installed_by_default": true + }, + "eemcgdkfndhakfknompkggombfjjjeno": { + "active_permissions": { + "api": [ "bookmarks", "bookmarkManagerPrivate", "metricsPrivate", "systemPrivate", "tabs" ], + "explicit_host": [ "chrome://favicon/*", "chrome://resources/*" ], + "manifest_permissions": [ ] + }, + "content_settings": [ ], + "creation_flags": 1, + "events": [ ], + "from_bookmark": false, + "from_webstore": false, + "incognito_content_settings": [ ], + "incognito_preferences": { + + }, + "initial_keybindings_set": true, + "install_time": "13039532121147000", + "location": 5, + "manifest": { + "chrome_url_overrides": { + "bookmarks": "main.html" + }, + "content_security_policy": "object-src 'none'; script-src chrome://resources 'self'", + "description": "Bookmark Manager", + "icons": { + + }, + "incognito": "split", + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQcByy+eN9jzazWF/DPn7NW47sW7lgmpk6eKc0BQM18q8hvEM3zNm2n7HkJv/R6fU+X5mtqkDuKvq5skF6qqUF4oEyaleWDFhd1xFwV7JV+/DU7bZ00w2+6gzqsabkerFpoP33ZRIw7OviJenP0c0uWqDWF8EGSyMhB3txqhOtiQIDAQAB", + "manifest_version": 2, + "name": "Bookmark Manager", + "permissions": [ "bookmarks", "bookmarkManagerPrivate", "metricsPrivate", "systemPrivate", "tabs", "chrome://favicon/", "chrome://resources/" ], + "version": "0.1" + }, + "path": "C:\\Program Files\\Google\\Chrome\\Application\\33.0.1750.154\\resources\\bookmark_manager", + "preferences": { + + }, + "regular_only_preferences": { + + }, + "was_installed_by_default": false + }, + "ennkphjdgehloodpbhlhldgbnhmacadg": { + "active_permissions": { + "api": [ "app.currentWindowInternal", "app.runtime", "app.window" ], + "explicit_host": [ "chrome://settings-frame/*" ], + "manifest_permissions": [ ] + }, + "content_settings": [ ], + "creation_flags": 1, + "events": [ "app.runtime.onLaunched" ], + "from_bookmark": false, + "from_webstore": false, + "incognito_content_settings": [ ], + "incognito_preferences": { + + }, + "initial_keybindings_set": true, + "install_time": "13039532121163000", + "location": 5, + "manifest": { + "app": { + "background": { + "scripts": [ "settings_app.js" ] + } + }, + "description": "Settings", + "display_in_launcher": false, + "icons": { + "128": "settings_app_icon_128.png", + "16": "settings_app_icon_16.png", + "32": "settings_app_icon_32.png", + "48": "settings_app_icon_48.png" + }, + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDoVDPGX6fvKPVVgc+gnkYlGqHuuapgFDyKhsy4z7UzRLO/95zXPv8h8e5EacqbAQJLUbP6DERH5jowyNEYVxq9GJyntJMwP1ejvoz/52hnY3CCGGCmttmKzzpp5zwLuq3iZf8bslwywfflNUYtaCFSDa0TtrBZz0aOPrAAd/AhNwIDAQAB", + "manifest_version": 2, + "name": "Settings", + "permissions": [ "chrome://settings-frame/" ], + "version": "0.2" + }, + "path": "C:\\Program Files\\Google\\Chrome\\Application\\33.0.1750.154\\resources\\settings_app", + "preferences": { + + }, + "regular_only_preferences": { + + }, + "running": false, + "was_installed_by_default": false + }, + "gfdkimpbcpahaombhbimeihdjnejgicl": { + "active_permissions": { + "api": [ "app.currentWindowInternal", "app.runtime", "app.window", "feedbackPrivate" ], + "explicit_host": [ "chrome://resources/*" ], + "manifest_permissions": [ ] + }, + "content_settings": [ ], + "creation_flags": 1, + "events": [ "feedbackPrivate.onFeedbackRequested" ], + "from_bookmark": false, + "from_webstore": false, + "incognito_content_settings": [ ], + "incognito_preferences": { + + }, + "initial_keybindings_set": true, + "install_time": "13039532121163000", + "location": 5, + "manifest": { + "app": { + "background": { + "scripts": [ "js/event_handler.js" ] + }, + "content_security_policy": "default-src 'none'; script-src 'self' chrome://resources; style-src 'unsafe-inline' *; img-src *; media-src 'self'" + }, + "description": "User feedback extension", + "display_in_launcher": false, + "display_in_new_tab_page": false, + "icons": { + "32": "images/icon32.png", + "64": "images/icon64.png" + }, + "incognito": "split", + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMZElzFX2J1g1nRQ/8S3rg/1CjFyDltWOxQg+9M8aVgNVxbutEWFQz+oQzIP9BB67mJifULgiv12ToFKsae4NpEUR8sPZjiKDIHumc6pUdixOm8SJ5Rs16SMR6+VYxFUjlVW+5CA3IILptmNBxgpfyqoK0qRpBDIhGk1KDEZ4zqQIDAQAB", + "manifest_version": 2, + "name": "Feedback", + "permissions": [ "feedbackPrivate", "chrome://resources/" ], + "version": "1.0" + }, + "path": "C:\\Program Files\\Google\\Chrome\\Application\\33.0.1750.154\\resources\\feedback", + "preferences": { + + }, + "regular_only_preferences": { + + }, + "running": false, + "was_installed_by_default": false + }, + "mfehgcgbbipciphmccgaenjidiccnmng": { + "active_permissions": { + "api": [ "cloudPrintPrivate" ], + "manifest_permissions": [ ] + }, + "content_settings": [ ], + "creation_flags": 1, + "events": [ ], + "from_bookmark": false, + "from_webstore": false, + "incognito_content_settings": [ ], + "incognito_preferences": { + + }, + "install_time": "13039532121147000", + "location": 5, + "manifest": { + "app": { + "launch": { + "web_url": "https://www.google.com/cloudprint" + }, + "urls": [ "https://www.google.com/cloudprint/enable_chrome_connector" ] + }, + "description": "Cloud Print", + "display_in_launcher": false, + "icons": { + + }, + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDqOhnwk4+HXVfGyaNsAQdU/js1Na56diW08oF1MhZiwzSnJsEaeuMN9od9q9N4ZdK3o1xXOSARrYdE+syV7Dl31nf6qz3A6K+D5NHe6sSB9yvYlIiN37jdWdrfxxE0pRYEVYZNTe3bzq3NkcYJlOdt1UPcpJB+isXpAGUKUvt7EQIDAQAB", + "name": "Cloud Print", + "permissions": [ "cloudPrintPrivate" ], + "version": "0.1" + }, + "path": "C:\\Program Files\\Google\\Chrome\\Application\\33.0.1750.154\\resources\\cloud_print", + "preferences": { + + }, + "regular_only_preferences": { + + }, + "was_installed_by_default": false + }, + "mgndgikekgjfcpckkfioiadnlibdjbkf": { + "active_permissions": { + "api": [ ], + "manifest_permissions": [ ] + }, + "app_launcher_ordinal": "n", + "content_settings": [ ], + "creation_flags": 1, + "events": [ ], + "from_bookmark": false, + "from_webstore": false, + "incognito_content_settings": [ ], + "incognito_preferences": { + + }, + "install_time": "13039532121163000", + "location": 5, + "manifest": { + "app": { + "launch": { + "web_url": "http://THIS-WILL-BE-REPLACED" + } + }, + "description": "Chrome as an app", + "display_in_launcher": true, + "display_in_new_tab_page": false, + "icons": { + "128": "product_logo_128.png", + "16": "product_logo_16.png" + }, + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDNuYLEQ1QPMcc5HfWI/9jiEf6FdJWqEtgRmIeI7qtjPLBM5oje+Ny2E2mTAhou5qdJiO2CHWdU1DQXY2F7Zu2gZaKZgHLfK4WimHxUT5Xd9/aro/R9PCzjguM1BLusiWYc9xlj1IsZpyiN1hcjU7SCnBhv1feQlv2WSB5KRiXwhQIDAQAB", + "name": "Chrome", + "version": "0.1" + }, + "page_ordinal": "n", + "path": "C:\\Program Files\\Google\\Chrome\\Application\\33.0.1750.154\\resources\\chrome_app", + "preferences": { + + }, + "regular_only_preferences": { + + }, + "was_installed_by_default": false + }, + "neajdppkdcdipfabeoofebfddakdcjhd": { + "active_permissions": { + "api": [ "systemPrivate", "ttsEngine" ], + "explicit_host": [ "https://www.google.com/*" ], + "manifest_permissions": [ ] + }, + "content_settings": [ ], + "creation_flags": 1, + "events": [ "ttsEngine.onPause", "ttsEngine.onResume", "ttsEngine.onSpeak", "ttsEngine.onStop" ], + "from_bookmark": false, + "from_webstore": false, + "incognito_content_settings": [ ], + "incognito_preferences": { + + }, + "initial_keybindings_set": true, + "install_time": "13039532121163000", + "location": 5, + "manifest": { + "background": { + "persistent": false, + "scripts": [ "tts_extension.js" ] + }, + "description": "Component extension providing speech via the Google network text-to-speech service.", + "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8GSbNUMGygqQTNDMFGIjZNcwXsHLzkNkHjWbuY37PbNdSDZ4VqlVjzbWqODSe+MjELdv5Keb51IdytnoGYXBMyqKmWpUrg+RnKvQ5ibWr4MW9pyIceOIdp9GrzC1WZGgTmZismYR3AjaIpufZ7xDdQQv+XrghPWCkdVqLN+qZDA1HU+DURznkMICiDDSH2sU0egm9UbWfS218bZqzKeQDiC3OnTPlaxcbJtKUuupIm5knjze3Wo9Ae9poTDMzKgchg0VlFCv3uqox+wlD8sjXBoyBCCK9HpImdVAF1a7jpdgiUHpPeV/26oYzM9/grltwNR3bzECQgSpyXp0eyoegwIDAQAB", + "manifest_version": 2, + "name": "Google Network Speech", + "permissions": [ "systemPrivate", "ttsEngine", "https://www.google.com/" ], + "tts_engine": { + "voices": [ { + "event_types": [ "start", "end", "error" ], + "gender": "female", + "lang": "en-US", + "remote": true, + "voice_name": "Google US English" + }, { + "event_types": [ "start", "end", "error" ], + "gender": "male", + "lang": "en-GB", + "remote": true, + "voice_name": "Google UK English Male" + }, { + "event_types": [ "start", "end", "error" ], + "gender": "female", + "lang": "en-GB", + "remote": true, + "voice_name": "Google UK English Female" + }, { + "event_types": [ "start", "end", "error" ], + "gender": "female", + "lang": "es-ES", + "remote": true, + "voice_name": "Google Español" + }, { + "event_types": [ "start", "end", "error" ], + "gender": "female", + "lang": "fr-FR", + "remote": true, + "voice_name": "Google Français" + }, { + "event_types": [ "start", "end", "error" ], + "gender": "female", + "lang": "it-IT", + "remote": true, + "voice_name": "Google Italiano" + }, { + "event_types": [ "start", "end", "error" ], + "gender": "female", + "lang": "de-DE", + "remote": true, + "voice_name": "Google Deutsch" + }, { + "event_types": [ "start", "end", "error" ], + "gender": "female", + "lang": "ja-JP", + "remote": true, + "voice_name": "Google ???" + }, { + "event_types": [ "start", "end", "error" ], + "gender": "female", + "lang": "ko-KR", + "remote": true, + "voice_name": "Google ???" + }, { + "event_types": [ "start", "end", "error" ], + "gender": "female", + "lang": "zh-CN", + "remote": true, + "voice_name": "Google ???" + } ] + }, + "version": "1.0" + }, + "path": "C:\\Program Files\\Google\\Chrome\\Application\\33.0.1750.154\\resources\\network_speech_synthesis", + "preferences": { + + }, + "regular_only_preferences": { + + }, + "was_installed_by_default": false + }, + "nkeimhogjdpnpccoofpliimaahmaaome": { + "active_permissions": { + "api": [ "alarms", "desktopCapture", "webConnectable", "webrtcAudioPrivate", "webrtcLoggingPrivate", "system.cpu" ], + "manifest_permissions": [ ] + }, + "content_settings": [ ], + "creation_flags": 1, + "events": [ "alarms.onAlarm", "runtime.onStartup" ], + "from_bookmark": false, + "from_webstore": false, + "incognito_content_settings": [ ], + "incognito_preferences": { + + }, + "initial_keybindings_set": true, + "install_time": "13039532121163000", + "location": 5, + "manifest": { + "background": { + "page": "background.html", + "persistent": false + }, + "externally_connectable": { + "matches": [ "https://*.google.com/hangouts*", "*://localhost/*" ] + }, + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDAQt2ZDdPfoSe/JI6ID5bgLHRCnCu9T36aYczmhw/tnv6QZB2I6WnOCMZXJZlRdqWc7w9jo4BWhYS50Vb4weMfh/I0On7VcRwJUgfAxW2cHB+EkmtI1v4v/OU24OqIa1Nmv9uRVeX0GjhQukdLNhAE6ACWooaf5kqKlCeK+1GOkQIDAQAB", + "manifest_version": 2, + "name": "Hangout Services", + "permissions": [ "alarms", "desktopCapture", "system.cpu", "webrtcAudioPrivate", "webrtcLoggingPrivate" ], + "version": "1.0" + }, + "path": "C:\\Program Files\\Google\\Chrome\\Application\\33.0.1750.154\\resources\\hangout_services", + "preferences": { + + }, + "regular_only_preferences": { + + }, + "was_installed_by_default": false + }, + "nmmhkkegccagdldgiimedpiccmgmieda": { + "ack_external": true, + "active_permissions": { + "api": [ "app.currentWindowInternal", "app.runtime", "app.window", "identity", "webRequestInternal", "webview" ], + "explicit_host": [ "https://checkout.google.com/*", "https://sandbox.google.com/*", "https://www.google.com/*", "https://www.googleapis.com/*" ], + "manifest_permissions": [ ] + }, + "content_settings": [ ], + "creation_flags": 137, + "events": [ "app.runtime.onLaunched" ], + "from_bookmark": false, + "from_webstore": true, + "incognito_content_settings": [ ], + "incognito_preferences": { + + }, + "initial_keybindings_set": true, + "install_time": "13039532125950599", + "lastpingday": "13039513199557599", + "location": 10, + "manifest": { + "app": { + "background": { + "scripts": [ "craw_background.js" ] + } + }, + "current_locale": "ru", + "default_locale": "en", + "description": "Google ??????? ??? ???????? ???????", + "display_in_launcher": false, + "display_in_new_tab_page": false, + "icons": { + "128": "images/icon_128.png", + "16": "images/icon_16.png" + }, + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrKfMnLqViEyokd1wk57FxJtW2XXpGXzIHBzv9vQI/01UsuP0IV5/lj0wx7zJ/xcibUgDeIxobvv9XD+zO1MdjMWuqJFcKuSS4Suqkje6u+pMrTSGOSHq1bmBVh0kpToN8YoJs/P/yrRd7FEtAXTaFTGxQL4C385MeXSjaQfiRiQIDAQAB", + "manifest_version": 2, + "minimum_chrome_version": "29", + "name": "Google ???????", + "oauth2": { + "auto_approve": true, + "client_id": "203784468217.apps.googleusercontent.com", + "scopes": [ "https://www.googleapis.com/auth/sierra", "https://www.googleapis.com/auth/sierrasandbox", "https://www.googleapis.com/auth/chromewebstore", "https://www.googleapis.com/auth/chromewebstore.readonly" ] + }, + "permissions": [ "identity", "webview", "https://checkout.google.com/", "https://sandbox.google.com/checkout/", "https://www.google.com/", "https://www.googleapis.com/*" ], + "update_url": "https://clients2.google.com/service/update2/crx", + "version": "0.0.6.1" + }, + "path": "nmmhkkegccagdldgiimedpiccmgmieda\\0.0.6.1_0", + "preferences": { + + }, + "regular_only_preferences": { + + }, + "running": false, + "state": 1, + "was_installed_by_default": true + }, + "pjkljhegncpnkpknbcohdijeoejaedia": { + "ack_external": true, + "active_permissions": { + "api": [ "notifications" ], + "manifest_permissions": [ ] + }, + "app_launcher_ordinal": "y", + "content_settings": [ ], + "creation_flags": 137, + "events": [ ], + "from_bookmark": false, + "from_webstore": true, + "granted_permissions": { + "api": [ "notifications" ], + "manifest_permissions": [ ] + }, + "incognito_content_settings": [ ], + "incognito_preferences": { + + }, + "install_time": "13039532128003599", + "lastpingday": "13039513199557599", + "location": 1, + "manifest": { + "app": { + "launch": { + "container": "tab", + "web_url": "https://mail.google.com/mail/ca" + }, + "urls": [ "*://mail.google.com/mail/ca" ] + }, + "current_locale": "ru", + "default_locale": "en", + "description": "??????? ????? ??? ?????, ? ??????? ????? ????? ????? ??????.", + "icons": { + "128": "128.png" + }, + "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCuGglK43iAz3J9BEYK/Mz6ZhloIMMDqQSAaf3vJt4eHbTbSDsu4WdQ9dQDRcKlg8nwQdePBt0C3PSUBtiSNSS37Z3qEGfS7LCju3h6pI1Yr9MQtxw+jUa7kXXIS09VV73pEFUT/F7c6Qe8L5ZxgAcBvXBh1Fie63qb02I9XQ/CQIDAQAB", + "name": "Gmail", + "options_page": "https://mail.google.com/mail/ca/#settings", + "permissions": [ "notifications" ], + "update_url": "http://clients2.google.com/service/update2/crx", + "version": "7" + }, + "page_ordinal": "n", + "path": "pjkljhegncpnkpknbcohdijeoejaedia\\7_1", + "preferences": { + + }, + "regular_only_preferences": { + + }, + "state": 1, + "was_installed_by_default": true + } + } + }, + "google": { + "services": { + "signin": { + "LSID": "", + "SID": "" + } + } + }, + "intl": { + "accept_languages": "ru-RU,ru,en-US,en" + }, + "invalidator": { + "client_id": "74Cf4DoEgWG6IJy/9sVadA==" + }, + "media": { + "device_id_salt": "Pnq2GfzhDdJpVy0Q1hZhCg==" + }, + "net": { + "http_server_properties": { + "servers": { + "accounts.google.com:443": { + "alternate_protocol": { + "port": 443, + "protocol_str": "quic" + }, + "settings": { + "4": 100 + }, + "supports_spdy": true + }, + "accounts.youtube.com:443": { + "alternate_protocol": { + "port": 443, + "protocol_str": "quic" + }, + "settings": { + "4": 100 + }, + "supports_spdy": true + }, + "apis.google.com:443": { + "alternate_protocol": { + "port": 443, + "protocol_str": "quic" + }, + "settings": { + "4": 100 + }, + "supports_spdy": true + }, + "clients2.google.com:443": { + "alternate_protocol": { + "port": 443, + "protocol_str": "quic" + }, + "settings": { + "4": 100 + }, + "supports_spdy": true + }, + "clients2.googleusercontent.com:443": { + "alternate_protocol": { + "port": 443, + "protocol_str": "quic" + }, + "settings": { + "4": 100 + }, + "supports_spdy": true + }, + "developer.android.com:443": { + "alternate_protocol": { + "port": 443, + "protocol_str": "quic" + }, + "settings": { + "4": 100 + }, + "supports_spdy": true + }, + "fonts.googleapis.com:443": { + "alternate_protocol": { + "port": 443, + "protocol_str": "quic" + }, + "settings": { + "4": 100 + }, + "supports_spdy": true + }, + "oauth.googleusercontent.com:443": { + "alternate_protocol": { + "port": 443, + "protocol_str": "quic" + }, + "settings": { + "4": 100 + }, + "supports_spdy": true + }, + "ssl.google-analytics.com:443": { + "alternate_protocol": { + "port": 443, + "protocol_str": "quic" + }, + "settings": { + "4": 100 + }, + "supports_spdy": true + }, + "ssl.gstatic.com:443": { + "alternate_protocol": { + "port": 443, + "protocol_str": "quic" + }, + "settings": { + "4": 100 + }, + "supports_spdy": true + }, + "themes.googleusercontent.com:443": { + "alternate_protocol": { + "port": 443, + "protocol_str": "quic" + }, + "settings": { + "4": 100 + }, + "supports_spdy": true + }, + "tools.google.com:80": { + "alternate_protocol": { + "port": 80, + "protocol_str": "quic" + }, + "supports_spdy": false + }, + "www.google.com:443": { + "settings": { + "4": 100 + }, + "supports_spdy": true + }, + "www.google.ru:443": { + "settings": { + "4": 100 + }, + "supports_spdy": true + } + }, + "version": 2 + } + }, + "pinned_tabs": [ ], + "plugins": { + "migrated_to_pepper_flash": true, + "plugins_list": [ ], + "removed_old_component_pepper_flash_settings": true + }, + "profile": { + "avatar_index": 0, + "content_settings": { + "clear_on_exit_migrated": true, + "pattern_pairs": { + + }, + "pref_version": 1 + }, + "exit_type": "Normal", + "exited_cleanly": true, + "icon_version": 2, + "managed_user_id": "", + "name": "?????? ????????????" + }, + "session": { + "restore_on_startup_migrated": true, + "startup_urls_migration_time": "13039532121147000" + }, + "sync_promo": { + "startup_count": 1 + }, + "translate_blocked_languages": [ "ru" ], + "translate_whitelists": { + + }, + "variations_seed": "CigyMjQ0ZTcyMjY2MThkZGRiOWQwMjAwOTUzZjIxYzFlNzBkM2UyYTVmEoABChtBVkZvdW5kYXRpb25NYWNWaWRlb0NhcHR1cmUYxP7/lwU4AUIIRGlzYWJsZWRKJgoNRW5hYmxlZEJ5RmxhZxAAKhNlbmFibGUtYXZmb3VuZGF0aW9uSgsKB0VuYWJsZWQQMkoMCghEaXNhYmxlZBAyUgwSBDMzLiogACABKAESqAEKCEFzeW5jRG5zGMSUtpcFOABCCGRpc2FibGVkSg4KClN5c3RlbURuc0EQAEoOCgpTeXN0ZW1EbnNCEABKFwoTQXN5bmNEbnNOb0ZhbGxiYWNrQRAAShcKE0FzeW5jRG5zTm9GYWxsYmFja0IQAEoNCglBc3luY0Ruc0EQAEoNCglBc3luY0Ruc0IQAEoMCghkaXNhYmxlZBBkUgwSBDI2LiogAiADKAMSbgoIQXN5bmNEbnMYxPfplAU4AEIKU3lzdGVtRG5zQUoOCgpTeXN0ZW1EbnNBEBlKDgoKU3lzdGVtRG5zQhAZSg0KCUFzeW5jRG5zQRAZSg0KCUFzeW5jRG5zQhAZUhASBDI5LiogACABKAAoASgCEmkKCEFzeW5jRG5zGMSMw44FOABCCUFzeW5jRG5zQUoOCgpTeXN0ZW1EbnNBEDJKDgoKU3lzdGVtRG5zQhAySg0KCUFzeW5jRG5zQRAySg0KCUFzeW5jRG5zQhAyUgwSBDI4LiogAigBKAISawoIQXN5bmNEbnMYxIaKkQU4AEIJQXN5bmNEbnNBSg4KClN5c3RlbURuc0EQGUoOCgpTeXN0ZW1EbnNCEBlKDgoJQXN5bmNEbnNBENsDSg4KCUFzeW5jRG5zQhDbA1IMEgQyNi4qIAMoASgCEmoKCEFzeW5jRG5zGMT36ZQFOABCClN5c3RlbURuc0FKDwoKU3lzdGVtRG5zQRDCA0oPCgpTeXN0ZW1EbnNCEMIDSg0KCUFzeW5jRG5zQRAySg0KCUFzeW5jRG5zQhAyUgoSBDMxLiogAigAEqcIChpBdXRvY29tcGxldGVEeW5hbWljVHJpYWxfMhiAvOmjBTgBQhlEZWZhdWx0Q29udHJvbF9Nb2JpbGVCZXRhSjsKLUVuYWJsZUVudGl0eVN1Z2dlc3RfUjFfQW5kcm9pZEJldGFfRXhwZXJpbWVudBBGGJ+TygEgn5PKAUo4CipFbmFibGVFbnRpdHlTdWdnZXN0X1IxX0FuZHJvaWRCZXRhX0NvbnRyb2wQRhigk8oBIKCTygFKPAouRW5hYmxlUHJvZmlsZVN1Z2dlc3RfUjFfQW5kcm9pZEJldGFfRXhwZXJpbWVudBBGGKGTygEgoZPKAUo5CitFbmFibGVQcm9maWxlU3VnZ2VzdF9SMV9BbmRyb2lkQmV0YV9Db250cm9sEEYYopPKASCik8oBSkEKM0VuYWJsZVBlcnNvbmFsaXplZFN1Z2dlc3RfUjFfQW5kcm9pZEJldGFfRXhwZXJpbWVudBBGGKOTygEgo5PKAUo+CjBFbmFibGVQZXJzb25hbGl6ZWRTdWdnZXN0X1IxX0FuZHJvaWRCZXRhX0NvbnRyb2wQRhikk8oBIKSTygFKPAouRW5hYmxlUG9zdGZpeFN1Z2dlc3RfUjFfQW5kcm9pZEJldGFfRXhwZXJpbWVudBBGGKWTygEgpZPKAUo5CitFbmFibGVQb3N0Zml4U3VnZ2VzdF9SMV9BbmRyb2lkQmV0YV9Db250cm9sEEYYppPKASCmk8oBSksKPUVuYWJsZVplcm9TdWdnZXN0X1F1ZXJpZXNBbmRVcmxzX05vU0VSUF9Nb2JpbGVfUjFfQW5kcm9pZEJldGEQRhjPksoBIM+SygFKUgpERW5hYmxlWmVyb1N1Z2dlc3RfUXVlcmllc0FuZFVybHNDb250cm9sX05vU0VSUF9Nb2JpbGVfUjFfQW5kcm9pZEJldGEQRhjQksoBINCSygFKRgo4RW5hYmxlWmVyb1N1Z2dlc3RfUXVlcmllc19Pbmx5U0VSUF9Nb2JpbGVfUjJfQW5kcm9pZEJldGEQRhjRksoBINGSygFKTQo/RW5hYmxlWmVyb1N1Z2dlc3RfUXVlcmllc0NvbnRyb2xfT25seVNFUlBfTW9iaWxlX1IyX0FuZHJvaWRCZXRhEEYY0pLKASDSksoBSkAKMkVuYWJsZVplcm9TdWdnZXN0TW9zdFZpc2l0ZWRfTW9iaWxlX1IxX0FuZHJvaWRCZXRhEEYY05LKASDTksoBSkcKOUVuYWJsZVplcm9TdWdnZXN0Q29udHJvbE1vc3RWaXNpdGVkX01vYmlsZV9SMV9BbmRyb2lkQmV0YRBGGNSSygEg1JLKAUodChlEZWZhdWx0Q29udHJvbF9Nb2JpbGVCZXRhEBRSEhIMMzMuMC4xNzUwLjczIAIoBFjd0vGqBhKyBgoaQXV0b2NvbXBsZXRlRHluYW1pY1RyaWFsXzIYgLzpowU4AUIVRGVmYXVsdENvbnRyb2xfTW9iaWxlSjwKLkVuYWJsZVplcm9TdWdnZXN0X1F1ZXJpZXNBbmRVcmxzX05vU0VSUF9Nb2JpbGUQChjLhMoBIMuEygFKQwo1RW5hYmxlWmVyb1N1Z2dlc3RfUXVlcmllc0FuZFVybHNDb250cm9sX05vU0VSUF9Nb2JpbGUQChjMhMoBIMyEygFKPgowRW5hYmxlWmVyb1N1Z2dlc3RfUXVlcmllc0FuZFVybHNfSW5jbFNFUlBfTW9iaWxlEAoYzYTKASDNhMoBSkUKN0VuYWJsZVplcm9TdWdnZXN0X1F1ZXJpZXNBbmRVcmxzQ29udHJvbF9JbmNsU0VSUF9Nb2JpbGUQChjOhMoBIM6EygFKMQojRW5hYmxlWmVyb1N1Z2dlc3RNb3N0VmlzaXRlZF9Nb2JpbGUQChjPhMoBIM+EygFKOAoqRW5hYmxlWmVyb1N1Z2dlc3RDb250cm9sTW9zdFZpc2l0ZWRfTW9iaWxlEAoY0ITKASDQhMoBSjAKFkRpc2FibGVaZXJvU3VnZ2VzdEZsYWcQACoUZGlzYWJsZS16ZXJvLXN1Z2dlc3RKXgozRW5hYmxlWmVyb1N1Z2dlc3RfUXVlcmllc0FuZFVybHNfTm9TRVJQX01vYmlsZV9GbGFnEAAYy4TKASogZW5hYmxlLXplcm8tc3VnZ2VzdC1ldGhlci1ub3NlcnBKXgo1RW5hYmxlWmVyb1N1Z2dlc3RfUXVlcmllc0FuZFVybHNfSW5jbFNFUlBfTW9iaWxlX0ZsYWcQABjNhMoBKh5lbmFibGUtemVyby1zdWdnZXN0LWV0aGVyLXNlcnBKUwooRW5hYmxlWmVyb1N1Z2dlc3RNb3N0VmlzaXRlZF9Nb2JpbGVfRmxhZxAAGM+EygEqIGVuYWJsZS16ZXJvLXN1Z2dlc3QtbW9zdC12aXNpdGVkSiMKFURlZmF1bHRDb250cm9sX01vYmlsZRAoGNGEygEg0YTKAVIMEgQzMi4qIAAgASgEWN3S8aoGEosDChpBdXRvY29tcGxldGVEeW5hbWljVHJpYWxfMhiAvOmjBTgBQhtEZWZhdWx0Q29udHJvbF9Nb2JpbGVTdGFibGVKNAomTmF2U3VnZ2VzdFVuaWZpY2F0aW9uX0ExX0FuZHJvaWRTdGFibGUQARj6k8oBIPqTygFKNAomTmF2U3VnZ2VzdFVuaWZpY2F0aW9uX0EyX0FuZHJvaWRTdGFibGUQARj7k8oBIPuTygFKNAomTmF2U3VnZ2VzdFVuaWZpY2F0aW9uX0EzX0FuZHJvaWRTdGFibGUQARj8k8oBIPyTygFKNAomTmF2U3VnZ2VzdFVuaWZpY2F0aW9uX0E0X0FuZHJvaWRTdGFibGUQARj9k8oBIP2TygFKNAomTmF2U3VnZ2VzdFVuaWZpY2F0aW9uX0E1X0FuZHJvaWRTdGFibGUQARj+k8oBIP6TygFKHwobRGVmYXVsdENvbnRyb2xfTW9iaWxlU3RhYmxlEF9SExINMzMuMC4xNzUwLjEzNiADKARYoYj0pgwSwgUKGkF1dG9jb21wbGV0ZUR5bmFtaWNUcmlhbF8yGICUn5wFOAFCEERlZmF1bHRDb250cm9sXzBKMwokRW5hYmxlWmVyb1N1Z2dlc3RfUjhfQmV0YV9FeHBlcmltZW50EOgHGMuSygEgy5LKAUowCiFQUF9FbmFibGVaZXJvU3VnZ2VzdF9SN19CZXRhX0FybUIQ6AcYhJPKASCEk8oBSjgKKVBQX0VuYWJsZUVudGl0eVN1Z2dlc3RfUjlfQmV0YV9FeHBlcmltZW50EPQDGJmTygEgmZPKAUo1CiZQUF9FbmFibGVFbnRpdHlTdWdnZXN0X1I5X0JldGFfQ29udHJvbBD0Axiak8oBIJqTygFKMwokRW5hYmxlWmVyb1N1Z2dlc3RfUjdfQmV0YV9FeHBlcmltZW50EOgHGNqEygEg2oTKAUo5CipQUF9FbmFibGVQcm9maWxlU3VnZ2VzdF9SOV9CZXRhX0V4cGVyaW1lbnQQ9AMYm5PKASCbk8oBSjYKJ1BQX0VuYWJsZVByb2ZpbGVTdWdnZXN0X1I5X0JldGFfQ29udHJvbBD0Axick8oBIJyTygFKPgovUFBfRW5hYmxlUGVyc29uYWxpemVkU3VnZ2VzdF9SOV9CZXRhX0V4cGVyaW1lbnQQ9AMYnZPKASCdk8oBSjsKLFBQX0VuYWJsZVBlcnNvbmFsaXplZFN1Z2dlc3RfUjlfQmV0YV9Db250cm9sEPQDGJ6TygEgnpPKAUowCiFFbmFibGVaZXJvU3VnZ2VzdF9SN19CZXRhX0NvbnRyb2wQ6AcY24TKASDbhMoBSjAKIUVuYWJsZVplcm9TdWdnZXN0X1I4X0JldGFfQ29udHJvbBDoBxjMksoBIMySygFKFAoQRGVmYXVsdENvbnRyb2xfMBAAUg4SBDMzLiogAigAKAEoAli8ztRAElIKGkF1dG9jb21wbGV0ZUR5bmFtaWNUcmlhbF8yGICE3I8FOAFCDkRlZmF1bHRDb250cm9sShIKDkRlZmF1bHRDb250cm9sEGRSCCAAKAAoASgCElIKGkF1dG9jb21wbGV0ZUR5bmFtaWNUcmlhbF8yGICE3I8FOAFCDkRlZmF1bHRDb250cm9sShIKDkRlZmF1bHRDb250cm9sEGRSCCABKAAoASgCEo8BChpBdXRvY29tcGxldGVEeW5hbWljVHJpYWxfMBiAw9CMBTgBQhNMaXZlU3BlbGxpbmdDb250cm9sSiAKFkxpdmVTcGVsbGluZ0V4cGVyaW1lbnQQtgcYhoTKAUocChNMaXZlU3BlbGxpbmdDb250cm9sEDIYh4TKAVIUEgQyNi4qIAAgASACIAMoACgBKAIS6wYKGkF1dG9jb21wbGV0ZUR5bmFtaWNUcmlhbF8yGICUn5wFOAFCGERlZmF1bHRDb250cm9sX1IyX1N0YWJsZUo0CiZFbmFibGVaZXJvU3VnZ2VzdF9SNV9TdGFibGVfRXhwZXJpbWVudBABGM2SygEgzZLKAUo0CiZFbmFibGVaZXJvU3VnZ2VzdF9SM19TdGFibGVfRXhwZXJpbWVudBABGNiEygEg2ITKAUo0CiZFbmFibGVaZXJvU3VnZ2VzdF9SNl9TdGFibGVfRXhwZXJpbWVudBABGNWSygEg1ZLKAUoxCiNFbmFibGVaZXJvU3VnZ2VzdF9SM19TdGFibGVfQ29udHJvbBABGNmEygEg2YTKAUoxCiNFbmFibGVaZXJvU3VnZ2VzdF9SNV9TdGFibGVfQ29udHJvbBABGM6SygEgzpLKAUoxCiNFbmFibGVaZXJvU3VnZ2VzdF9SNl9TdGFibGVfQ29udHJvbBABGNaSygEg1pLKAUouCiBQb3N0cGVyaW9kX01vc3RWaXNpdGVkX1I2X1N0YWJsZRABGKeTygEgp5PKAUoxCiNQb3N0cGVyaW9kX1Jlc3RvcmVOYXZzdWdnZXN0X1N0YWJsZRABGJeTygEgl5PKAUo1CidQb3N0cGVyaW9kX01vc3RWaXNpdGVkQ29udHJvbF9SNl9TdGFibGUQARiok8oBIKiTygFKOAoqUG9zdHBlcmlvZF9SZXN0b3JlTmF2c3VnZ2VzdENvbnRyb2xfU3RhYmxlEAEYmJPKASCYk8oBSi0KH05hdlN1Z2dlc3RVbmlmaWNhdGlvbl9BMV9TdGFibGUQARirk8oBIKuTygFKLQofTmF2U3VnZ2VzdFVuaWZpY2F0aW9uX0EyX1N0YWJsZRABGKyTygEgrJPKAUotCh9OYXZTdWdnZXN0VW5pZmljYXRpb25fQTNfU3RhYmxlEAEYrZPKASCtk8oBSi0KH05hdlN1Z2dlc3RVbmlmaWNhdGlvbl9BNF9TdGFibGUQARiuk8oBIK6TygFKLQofTmF2U3VnZ2VzdFVuaWZpY2F0aW9uX0E1X1N0YWJsZRABGP+TygEg/5PKAUocChhEZWZhdWx0Q29udHJvbF9SMl9TdGFibGUQVVIOEgQzMC4qIAMoACgBKAJYvM7UQBKGAQoVQXV0b21hdGljUHJvZmlsZVJlc2V0GMTxsJcFOAFCCERpc2FibGVkShgKFERpc2FibGVkQ29udHJvbEdyb3VwEApKCgoGRHJ5UnVuEApKCwoHRW5hYmxlZBAASgwKCERpc2FibGVkEFBSFRILMzIuMC4xNzAwLjAgAigAKAEoAljulLVREoMBChVBdXRvbWF0aWNQcm9maWxlUmVzZXQYxPGwlwU4AUIIRGlzYWJsZWRKGAoURGlzYWJsZWRDb250cm9sR3JvdXAQIUoKCgZEcnlSdW4QIUoLCgdFbmFibGVkEABKDAoIRGlzYWJsZWQQIVIXEgszMi4wLjE2ODYuMCAAIAEoACgBKAISpw8KFUF1dG9tYXRpY1Byb2ZpbGVSZXNldBjE2sCXBTgBQghEaXNhYmxlZEoYChREaXNhYmxlZENvbnRyb2xHcm91cBAASgoKBkRyeVJ1bhAASgsKB0VuYWJsZWQQAUqFDgoIRW5hYmxlZDMQATItCgloYXNoX3NlZWQSIGY1ODVlYWI4YzVjZGJiMzk1MDViYmFmZDQwMjYwNDQ3MscNCgdwcm9ncmFtErsNAEQ0MjNDNzQ4OTlCNDA4NDIxRjRFODA1OTczRTBGMjI0IUQxMjM0MkQ5RkNENjkzQUM1RjIyNUQwOEY5ODc2RTY4EENERkJGOTJCODVFRkI5QjI4NjlERkZDQUQ4Q0NFMjM0ARA5NERCRTFDQ0YxQzU2RUEzODBGN0E5MjBGNUI1NEIwMAExADdBMzdGQ0I5N0RFODZFMjFEQjNDNjExQjZBRDg5NzJDIUQxMjM0MkQ5RkNENjkzQUM1RjIyNUQwOEY5ODc2RTY4EDQ3NDk3QUMzQTFFMEUzNkJEMEY0MzU1RkFBRDU3QjQ3ARA5NERCRTFDQ0YxQzU2RUEzODBGN0E5MjBGNUI1NEIwMAExAEJCNzFDRjE5MTdEQzFCMjY4NEQ2MDlGNDI4NzNCRUJCIUQxMjM0MkQ5RkNENjkzQUM1RjIyNUQwOEY5ODc2RTY4EEY5QzcwQkQ4RkRDMTkwRjg5MkU3ODNENjcxQkYzQzJGARA5NERCRTFDQ0YxQzU2RUEzODBGN0E5MjBGNUI1NEIwMAExEkRGNDAwRUMyOTBEQ0QyNDBERTU3NkUxNzQ5MDI2MERBODE0MDgzNjdGNzcxNjBENjUyN0Q2RTA4MjlFMDc0OTExAEZDOTk2NzE4OTBFOUQ3QUE0NzJBQUVBRjhDNzQzRTREAEIzNzcxNTcwMUI2QTAwMTg2MEZGMTQ3MTQ3NkYzMjg3FURGNDAwRUMyOTBEQ0QyNDBERTU3NkUxNzQ5MDI2MERBMQA1MEIzMUUwNzZFRDZFOThGNzVERDAzMjAxMEQwQzgxQQEAQjM3NzE1NzAxQjZBMDAxODYwRkYxNDcxNDc2RjMyODckREY0MDBFQzI5MERDRDI0MERFNTc2RTE3NDkwMjYwREEQRTU2MEIzRTQ5MzY5QjkwMDY2NzZCOTFDQkM3NUFFQTYBMQAwN0U4QUY3NEZCOThGN0NGMTRDNEZBNjdFNzhDQzBCMyABEUU1NjBCM0U0OTM2OUI5MDA2Njc2QjkxQ0JDNzVBRUE2AAAQM0I1MTJFMjNBNEY2MEU3Qjk5QTk4N0Y4RTUwN0NBNjYBMQA5QkVDMjQyMUNDQzRENTFEMzU1RDY3NkJFOTE5QzdBQgBFMTIwQUNGNUVFRURBQjQwNDExQTE2RTUxNDcyRjdFMAA5NDdBQjA3MzA0NzI0QUQ0MEQ0MDA4MjJERTlGRUQ4OAEARTU4RDY1OEIwNUVGRTA1MzEwQThEM0E2NzcyRURFMzUhOUY1OTdBQTAwOEJBRDdCNThGQUNCN0Q2OEJDRTc5RDUCADBBMjQ3MjZGNzJGRkNDNzRBODc2NDkyRTA3QjlERDBDIjJCQkQ4M0E3RUZGOUNBNzQ0NEY4RkE4RTQ1QTNDNkMyIjE0RDJENTAwNDlFMUE1M0VDQzZCQzVFMzg4NTI4QTMwIjRFNEY0M0VDREQ3QkU4REE3M0JDNjU3N0FBRDhFRDY0AgA5QTdEQjI3RDQzQTYyMzA1QkIyNTEzQjcyODcxOEFCNCAAAgBBRDExRENCQkZBNDdFN0FDMkEyQzEwNkVCNDYxMTMwMwA3RDYwMzY2N0Y2RUI2QTlFQzkxMDFGOTFFRUY0M0Q4NwAwQTAxNDE2ODU2NkM4ODcxRDhGMjAyQzRBNjY3ODNEMSJGRUM1OTM0RTY0MkI3RDUxREM4MkEzM0M5M0VBRUZBNwICAhAyMTgxOUY3ODU2Q0UyQUI1REYwNzQzQkJCOUY3QTY0RgExETNCNTEyRTIzQTRGNjBFN0I5OUE5ODdGOEU1MDdDQTY2AQAQMzRCNkMyNTBDODRCRTYzMTM3REJGMTRDNkI0ODhDMTcBEEExN0QzRDMzRkY0OUE0OTBCQkI4MjUwRkFFODNBMjMwATERMjE4MTlGNzg1NkNFMkFCNURGMDc0M0JCQjlGN0E2NEYBABAzNEI2QzI1MEM4NEJFNjMxMzdEQkYxNEM2QjQ4OEMxNwEQQTE3RDNEMzNGRjQ5QTQ5MEJCQjgyNTBGQUU4M0EyMzABMRJENDIzQzc0ODk5QjQwODQyMUY0RTgwNTk3M0UwRjIyNDg5MWU0MmMyMTQ2YjM3YjNkMTY5OGM1ZDg0YzJhYmQzMRI3QTM3RkNCOTdERTg2RTIxREIzQzYxMUI2QUQ4OTcyQzg5MWU0MmMyMTQ2YjM3YjNkMTY5OGM1ZDg0YzJhYmQzMRJCQjcxQ0YxOTE3REMxQjI2ODRENjA5RjQyODczQkVCQjg5MWU0MmMyMTQ2YjM3YjNkMTY5OGM1ZDg0YzJhYmQzMUoMCghFbmFibGVkNBBiSgwKCERpc2FibGVkEABSHwiQra+XBRINMzIuMC4xNzAwLjEwMhoEMzIuKiADKABYxpKv7Q4SUQoQQnJvd3NlckJsYWNrbGlzdBjAosWdBTgBQgtOb0JsYWNrbGlzdEoLCgdFbmFibGVkEDJKDwoLTm9CbGFja2xpc3QQMlIKEgQzNC4qIAIoABJTChBCcm93c2VyQmxhY2tsaXN0GMCixZ0FOAFCC05vQmxhY2tsaXN0SgsKB0VuYWJsZWQQZEoPCgtOb0JsYWNrbGlzdBAAUgwSBDM0LiogACABKAASVAoKQ0xEMVZzQ0xEMhjE3oWUBTgBQgdEZWZhdWx0SggKBENMRDEQAUoICgRDTEQyEAFKCwoHRGVmYXVsdBBiUhQaBDMxLiogACABIAIoACgBKAMoAhKSAQoYQ2FjaGVTZW5zaXRpdml0eUFuYWx5c2lzGMT10o4FOABCAk5vSgwKCENvbnRyb2xBEAVKDAoIQ29udHJvbEIQBUoICgQxMDBBEAVKCAoEMTAwQhAFSggKBDIwMEEQBUoICgQyMDBCEAVKCAoENDAwQRAFSggKBDQwMEIQBUoGCgJObxA8UgoSBDI4LiogAigEEn8KGENhY2hlU2Vuc2l0aXZpdHlBbmFseXNpcxjEjrePBTgAQgJOb0oMCghDb250cm9sQRABSgwKCENvbnRyb2xCEAFKCAoEMTAwQRABSggKBDEwMEIQAUoICgQyMDBBEAFKCAoEMjAwQhABSgcKAk5vEOIHUgoSBDI4LiogAygEEpoBChhDYWNoZVNlbnNpdGl2aXR5QW5hbHlzaXMYxMr9igU4AEICTm9KBgoCTm8QJEoMCghDb250cm9sQRAISgwKCENvbnRyb2xCEAhKCAoEMTAwQRAISggKBDEwMEIQCEoICgQyMDBBEAhKCAoEMjAwQhAISggKBDQwMEEQCEoICgQ0MDBCEAhSEhIEMjUuKiAAIAEgAigAKAEoAhKdAQoYQ2FjaGVTZW5zaXRpdml0eUFuYWx5c2lzGMSy04oFOABCAk5vSgcKAk5vEOAHSgwKCENvbnRyb2xBEAFKDAoIQ29udHJvbEIQAUoICgQxMDBBEAFKCAoEMTAwQhABSggKBDIwMEEQAUoICgQyMDBCEAFKCAoENDAwQRABSggKBDQwMEIQAVIUCICnvooFEgQyNS4qIAMoACgBKAISsAEKEUNocm9tZVN1Z2dlc3Rpb25zOAFCB0RlZmF1bHRKFQoHQ29udHJvbBAAGMqIygEgyojKAUpcCgdFbmFibGVkEAAYy4jKASDLiMoBMhAKBXN0YXRlEgdlbmFibGVkMjMKA3VybBIsaHR0cHM6Ly93d3cuZ29vZ2xlLmNvbS9jaHJvbWVzdWdnZXN0aW9ucz90PTFKCwoHRGVmYXVsdBBkUgwSBDM0LiogACABKARgARLdAQoRQ2hyb21lU3VnZ2VzdGlvbnMYxPyunAU4AUIHRGVmYXVsdEoaCgxDb250cm9sIGJldGEQFBiziMoBILOIygFKIwoVTUwgTm8tS29kYWNocm9tZSBiZXRhEBQYtIjKASC0iMoBSiAKEk1MIEtvZGFjaHJvbWUgYmV0YRAUGMeIygEgx4jKAUolChdNTCBOZXdzLUNvbnRpZ3VvdXMgYmV0YRAAGNeIygEg14jKAUoVCgdEZWZhdWx0ECgYtYjKASC1iMoBUg4SBDMyLiogAigAKAEoA1jul+34C2ABEt0BChFDaHJvbWVTdWdnZXN0aW9ucxjE/K6cBTgBQgdEZWZhdWx0ShkKC0NvbnRyb2wgZGV2EBQYsIjKASCwiMoBSiIKFE1MIE5vLUtvZGFjaHJvbWUgZGV2EBQYsYjKASCxiMoBSh8KEU1MIEtvZGFjaHJvbWUgZGV2EBQYxojKASDGiMoBSiQKFk1MIE5ld3MtQ29udGlndW91cyBkZXYQABi9iMoBIL2IygFKFQoHRGVmYXVsdBAoGLKIygEgsojKAVISEgQzMi4qIAAgASgAKAEoAygCWO6X7fgLYAESwwEKEUNocm9tZVN1Z2dlc3Rpb25zGMSZ2JkFOAFCB0RlZmF1bHRKFQoHQ29udHJvbBAFGLaIygEgtojKAUosCh5Nb3N0IExpa2VseSB3aXRob3V0IEtvZGFjaHJvbWUQBRi3iMoBILeIygFKKQobTW9zdCBMaWtlbHkgd2l0aCBLb2RhY2hyb21lEAUYuIjKASC4iMoBShUKB0RlZmF1bHQQVRi5iMoBILmIygFSDhIEMzIuKiADKAAoASgDWOTyxPcGYAESvAEKEENvbnRleHR1YWxTZWFyY2gYxL6XpQU4AUIHRGVmYXVsdEopCgNUYXAQABjIiMoBIMiIygEyFgoPZXhwZXJpbWVudF9raW5kEgNUYXBKFQoHQ29udHJvbBAAGMmIygEgyYjKAUo4CglUYXBGb3JjZWQQACoRY29udGV4dHVhbC1zZWFyY2gyFgoPZXhwZXJpbWVudF9raW5kEgNUYXBKCwoHRGVmYXVsdBBkUg4SBDM0LiogACABKAQ4ARJ9ChxDb29raWVSZXRlbnRpb25Qcmlvcml0eVN0dWR5GMCXx5gFOAFCDEV4cGVyaW1lbnRPbkoWCg1FeHBlcmltZW50T2ZmEAAYlYrKAUoVCgxFeHBlcmltZW50T24QZBiWisoBUhgaBDMxLiogACABIAIgAygAKAEoAigDKAQSSAoPRDNEMTFFeHBlcmltZW50GIDa45EFOAFCCERpc2FibGVkSgwKCERpc2FibGVkEABKCwoHRW5hYmxlZBBkUggSBDI5LiooABJsCiNEYXRhQ29tcHJlc3Npb25Qcm94eVByZWNvbm5lY3RIaW50cxjEgPSYBTgBQghEaXNhYmxlZEoLCgdFbmFibGVkEGRKCwoHQ29udHJvbBBkSg0KCERpc2FibGVkEKAGUgoSBDMzLiogAigEEmEKI0RhdGFDb21wcmVzc2lvblByb3h5UHJlY29ubmVjdEhpbnRzGMSA9JgFOAFCCERpc2FibGVkSgwKB0VuYWJsZWQQ6AdKDAoIRGlzYWJsZWQQAFIMEgQzMy4qIAAgASgEElwKHkRhdGFDb21wcmVzc2lvblByb3h5RGV2Um9sbG91dBjE2amcBTgBQghEaXNhYmxlZEoLCgdFbmFibGVkEGRKDQoIRGlzYWJsZWQQhAdSDBIEMzQuKiAAIAEoBBJiCiNEYXRhQ29tcHJlc3Npb25Qcm94eVByb21vVmlzaWJpbGl0eRjEgpe0BTgBQgdFbmFibGVkSgwKCERpc2FibGVkEABKDAoHRW5hYmxlZBDoB1IOEgQzMS4qIAAgASACKAQSZgojRGF0YUNvbXByZXNzaW9uUHJveHlQcm9tb1Zpc2liaWxpdHkYxIKXtAU4AUIIRGlzYWJsZWRKDQoIRGlzYWJsZWQQ9ANKDAoHRW5hYmxlZBD0A1IQEgQzMS4qGgQzMS4qIAMoBBJfCiNEYXRhQ29tcHJlc3Npb25Qcm94eVByb21vVmlzaWJpbGl0eRjEgpe0BTgBQghEaXNhYmxlZEoNCghEaXNhYmxlZBCEB0oLCgdFbmFibGVkEGRSChIEMzIuKiADKAQSZQojRGF0YUNvbXByZXNzaW9uUHJveHlQcm9tb1Zpc2liaWxpdHkYxN6FlAU4AUIIRGlzYWJsZWRKDAoHRW5hYmxlZBDoB0oMCghEaXNhYmxlZBAAUhASBDMxLioaBDMxLiogAygFEmIKI0RhdGFDb21wcmVzc2lvblByb3h5UHJvbW9WaXNpYmlsaXR5GMSCl7QFOAFCB0VuYWJsZWRKDAoIRGlzYWJsZWQQAEoMCgdFbmFibGVkEOgHUg4SBDMwLiogACABIAIoBRKzAQojRGF0YUNvbXByZXNzaW9uUHJveHlQcm9tb1Zpc2liaWxpdHkYxIKXtAU4AUIIRGlzYWJsZWRKCwoHRW5hYmxlZBBkSg0KCERpc2FibGVkEIQHUl4SBDMyLiogAygFMgVlbi1VUzICZXMyAmphMgVlbi1HQjICdHIyAmZyMgJkZTIFemgtVFcyAmtvMgJpdDICYXIyAm5sMgJzdjICcGwyAmRhMgJuYjIFcHQtUFQyAmhlEpIBCiNEYXRhQ29tcHJlc3Npb25Qcm94eVByb21vVmlzaWJpbGl0eRjEgpe0BTgBQghEaXNhYmxlZEoMCgdFbmFibGVkEPQDSg0KCERpc2FibGVkEPQDUjwSBDMyLiogAygFMgJydTIFemgtQ04yAnB0MgJ2aTICdGgyBWVzLU1YMgJpZDIFcHQtQlIyA2ZpbDICaGkSWgobRGF0YUNvbXByZXNzaW9uUHJveHlSb2xsb3V0GMSCl7QFOAFCB0VuYWJsZWRKDAoIRGlzYWJsZWQQAEoMCgdFbmFibGVkEOgHUg4SBDI4LiogACABIAIoBBJdChtEYXRhQ29tcHJlc3Npb25Qcm94eVJvbGxvdXQYxIKXtAU4AUIIRGlzYWJsZWRKCwoHRW5hYmxlZBB4Sg0KCERpc2FibGVkEPAGUhASBDI4LioaBDMxLiogAygEElYKG0RhdGFDb21wcmVzc2lvblByb3h5Um9sbG91dBjEgpe0BTgBQgdFbmFibGVkSgwKCERpc2FibGVkEABKDAoHRW5hYmxlZBDoB1IKEgQzMi4qIAMoBBJdChtEYXRhQ29tcHJlc3Npb25Qcm94eVJvbGxvdXQYxLCllAU4AUIIRGlzYWJsZWRKDAoHRW5hYmxlZBDoB0oMCghEaXNhYmxlZBAAUhASBDMxLioaBDMxLiogAygFEloKG0RhdGFDb21wcmVzc2lvblByb3h5Um9sbG91dBjEgpe0BTgBQgdFbmFibGVkSgwKCERpc2FibGVkEABKDAoHRW5hYmxlZBDoB1IOEgQyOC4qIAAgASACKAUSagobRGF0YUNvbXByZXNzaW9uUHJveHlSb2xsb3V0GMSCl7QFOAFCCERpc2FibGVkSgsKB0VuYWJsZWQQeEoLCgdDb250cm9sEHhKDQoIRGlzYWJsZWQQ+AVSEBIEMjguKhoEMzEuKiADKAUSVwobRGF0YUNvbXByZXNzaW9uUHJveHlSb2xsb3V0GMSCl7QFOAFCCERpc2FibGVkSgwKB0VuYWJsZWQQ6AdKDAoIRGlzYWJsZWQQAFIKEgQzMi4qIAMoBRJXChZEYXRhQ29tcHJlc3Npb25JT1NXZWJQGMSCl7QFOAFCCERpc2FibGVkSgwKB0VuYWJsZWQQ9ANKDQoIRGlzYWJsZWQQ9ANSDhIEMzIuKiAAIAEgAigFElEKFkRhdGFDb21wcmVzc2lvbklPU1dlYlAYxIKXtAU4AUIHRW5hYmxlZEoMCghEaXNhYmxlZBAASgwKB0VuYWJsZWQQ6AdSChIEMzIuKiADKAUSXwoURGF0ZUV4dGVuc2lvbkVuYWJsZWQYxNeSlgU4AEIHRGVmYXVsdEoLCgdFbmFibGVkEDJKDAoIRGlzYWJsZWQQMkoLCgdEZWZhdWx0EABSDhIEMzIuKiAAIAEoACgEEnQKIERlZmVyQmFja2dyb3VuZEV4dGVuc2lvbkNyZWF0aW9uGMTtjqAFOAFCC1JhdGVMaW1pdGVkSgwKCERlZmVycmVkEABKDwoLUmF0ZUxpbWl0ZWQQZFIcEgQzMS4qGgQzMy4qIAAgASACIAMoACgBKAMoAhJEChFEbnNQcm9iZS1BdHRlbXB0cxiAtY2WBTgBQgdkZWZhdWx0SgsKB2RlZmF1bHQQWkoFCgExEApSChIEMjUuKiAAIAESRwoPRG5zUHJvYmUtRW5hYmxlGIC1jZYFOAFCB2Rpc2FibGVKCwoHZGlzYWJsZRAASgoKBmVuYWJsZRBkUgoSBDI1LiogACABEmMKI1VNQS1EeW5hbWljLUJpbmFyeS1Vbmlmb3JtaXR5LVRyaWFsGICckqUFOAFCB2RlZmF1bHRKEAoHZGVmYXVsdBABGKm2yQFKEQoIZ3JvdXBfMDEQARiqtskBUgYgACABIAISXwojVU1BLUR5bmFtaWMtQmluYXJ5LVVuaWZvcm1pdHktVHJpYWwYgJySpQU4AUIHZGVmYXVsdEoQCgdkZWZhdWx0EGMYqbbJAUoRCghncm91cF8wMRABGKq2yQFSAiADErMFCg5FbWJlZGRlZFNlYXJjaBjE0tmjBTgBQgxEZWZhdWx0R3JvdXBKHQoOR3JvdXAxIGJldGE6cjEQkAMYz4jKASDPiMoBSjAKIUdyb3VwMiBiZXRhOnIxIHByZWZldGNoX3Jlc3VsdHM6MRDIARjQiMoBINCIygFKUQpCR3JvdXAzIGJldGE6cjEgcHJlZmV0Y2hfcmVzdWx0czoxIHJldXNlX2luc3RhbnRfc2VhcmNoX2Jhc2VfcGFnZToxEMgBGNGIygEg0YjKAUocCg5Hcm91cDQgYmV0YTpyMhBkGNKIygEg0ojKAUo4CipHcm91cDUgYmV0YTpyMiBlc3B2OjIxMyBxdWVyeV9leHRyYWN0aW9uOjEQGRjTiMoBINOIygFKUApCR3JvdXA2IGJldGE6cjIgZXNwdjoyMTMgcXVlcnlfZXh0cmFjdGlvbjoxIGRpc3BsYXlfc2VhcmNoX2J1dHRvbjoxEBkY1IjKASDUiMoBSlAKQkdyb3VwNyBiZXRhOnIyIGVzcHY6MjEzIHF1ZXJ5X2V4dHJhY3Rpb246MSBkaXNwbGF5X3NlYXJjaF9idXR0b246MhAZGNWIygEg1YjKAUpECjZHcm91cDggYmV0YTpyMiBkaXNwbGF5X3NlYXJjaF9idXR0b246MiBoaWRlX3ZlcmJhdGltOjEQGRjWiMoBINaIygFKPwoOR3JvdXA5IGJldGE6ZjEQACorZW5hYmxlLW9yaWdpbi1jaGlwLXYyLWhpZGUtb24tbW91c2UtcmVsZWFzZUo9Cg9Hcm91cDEwIGJldGE6ZjEQACooZW5hYmxlLW9yaWdpbi1jaGlwLXYyLWhpZGUtb24tdXNlci1pbnB1dEoQCgxEZWZhdWx0R3JvdXAQAFIOEgQzMy4qIAIoACgBKANYxK+vXBLKCAoORW1iZWRkZWRTZWFyY2g4AUIMRGVmYXVsdEdyb3VwShsKDUdyb3VwMSBkZXY6cjMQDxjEiMoBIMSIygFKTwpBR3JvdXAyIGRldjpyMyBlc3B2OjIxMyBxdWVyeV9leHRyYWN0aW9uOjEgZGlzcGxheV9zZWFyY2hfYnV0dG9uOjEQDxi/iMoBIL+IygFKTwpBR3JvdXAzIGRldjpyMyBlc3B2OjIxMyBxdWVyeV9leHRyYWN0aW9uOjEgZGlzcGxheV9zZWFyY2hfYnV0dG9uOjIQDxjAiMoBIMCIygFKXwpRR3JvdXA0IGRldjpyMyBlc3B2OjIxMyBxdWVyeV9leHRyYWN0aW9uOjEgZGlzcGxheV9zZWFyY2hfYnV0dG9uOjIgaGlkZV92ZXJiYXRpbToxEA8YwYjKASDBiMoBShsKDUdyb3VwNSBkZXY6cjQQZBjMiMoBIMyIygFKLgogR3JvdXA2IGRldjpyNCBwcmVmZXRjaF9yZXN1bHRzOjEQZBjNiMoBIM2IygFKTwpBR3JvdXA3IGRldjpyNCBwcmVmZXRjaF9yZXN1bHRzOjEgcmV1c2VfaW5zdGFudF9zZWFyY2hfYmFzZV9wYWdlOjEQZBjOiMoBIM6IygFKHgoPR3JvdXAxMiBkZXY6cHA0EIwBGMWIygEgxYjKAUpPCjdHcm91cDggZGV2OmYxIGVzcHY6MjEzIHF1ZXJ5X2V4dHJhY3Rpb246MSBvcmlnaW5fY2hpcDoxEAAqEmVuYWJsZS1vcmlnaW4tY2hpcEptCkFHcm91cDkgZGV2OmYxIGVzcHY6MjEzIHF1ZXJ5X2V4dHJhY3Rpb246MSBkaXNwbGF5X3NlYXJjaF9idXR0b246MxAAKiZlbmFibGUtc2VhcmNoLWJ1dHRvbi1pbi1vbW5pYm94LWFsd2F5c0pvCkJHcm91cDEwIGRldjpmMSBlc3B2OjIxMyBxdWVyeV9leHRyYWN0aW9uOjEgZGlzcGxheV9zZWFyY2hfYnV0dG9uOjEQAConZW5hYmxlLXNlYXJjaC1idXR0b24taW4tb21uaWJveC1mb3Itc3RySnYKQkdyb3VwMTEgZGV2OmYxIGVzcHY6MjEzIHF1ZXJ5X2V4dHJhY3Rpb246MSBkaXNwbGF5X3NlYXJjaF9idXR0b246MhAAKi5lbmFibGUtc2VhcmNoLWJ1dHRvbi1pbi1vbW5pYm94LWZvci1zdHItb3ItaWlwSj8KDkdyb3VwMTIgZGV2OmYxEAAqK2VuYWJsZS1vcmlnaW4tY2hpcC12Mi1oaWRlLW9uLW1vdXNlLXJlbGVhc2VKPAoOR3JvdXAxMyBkZXY6ZjEQACooZW5hYmxlLW9yaWdpbi1jaGlwLXYyLWhpZGUtb24tdXNlci1pbnB1dEoQCgxEZWZhdWx0R3JvdXAQAFIQEgQzMy4qIAAgASgAKAEoAxLeDQoORW1iZWRkZWRTZWFyY2gYgKX5owU4AUIMRGVmYXVsdEdyb3VwSiYKGEdyb3VwMSBwY3Q6MTBhIHN0YWJsZTpyMRAKGNiIygEg2IjKAUpWCkhHcm91cDIgcGN0OjEwYiBzdGFibGU6cHAxIHVzZV9jYWNoZWFibGVfbnRwOjEgZXNwdjoyMTAgc3VwcHJlc3Nfb25fc3JwOjEQChieiMoBIJ6IygFKVgpIR3JvdXAzIHBjdDoxMGMgc3RhYmxlOnBwMSB1c2VfY2FjaGVhYmxlX250cDoxIGVzcHY6MjEwIHN1cHByZXNzX29uX3NycDoxEAoYn4jKASCfiMoBSlYKSEdyb3VwNCBwY3Q6MTBkIHN0YWJsZTpwcDEgdXNlX2NhY2hlYWJsZV9udHA6MSBlc3B2OjIxMCBzdXBwcmVzc19vbl9zcnA6MRAKGKCIygEgoIjKAUpWCkhHcm91cDUgcGN0OjEwZSBzdGFibGU6cHAxIHVzZV9jYWNoZWFibGVfbnRwOjEgZXNwdjoyMTAgc3VwcHJlc3Nfb25fc3JwOjEQChihiMoBIKGIygFKVgpIR3JvdXA2IHBjdDoxMGYgc3RhYmxlOnBwMSB1c2VfY2FjaGVhYmxlX250cDoxIGVzcHY6MjEwIHN1cHByZXNzX29uX3NycDoxEAoYoojKASCiiMoBSlYKSEdyb3VwNyBwY3Q6MTBnIHN0YWJsZTpwcDEgdXNlX2NhY2hlYWJsZV9udHA6MSBlc3B2OjIxMCBzdXBwcmVzc19vbl9zcnA6MRAKGKOIygEgo4jKAUpWCkhHcm91cDggcGN0OjEwaCBzdGFibGU6cHAxIHVzZV9jYWNoZWFibGVfbnRwOjEgZXNwdjoyMTAgc3VwcHJlc3Nfb25fc3JwOjEQChikiMoBIKSIygFKVgpIR3JvdXA5IHBjdDoxMGkgc3RhYmxlOnBwMSB1c2VfY2FjaGVhYmxlX250cDoxIGVzcHY6MjEwIHN1cHByZXNzX29uX3NycDoxEAoYpYjKASCliMoBSiYKGEdyb3VwMTAgcGN0OjFhIHN0YWJsZTpyMRABGNmIygEg2YjKAUo5CitHcm91cDExIHBjdDoxYiBzdGFibGU6cjEgcHJlZmV0Y2hfcmVzdWx0czoxEAEY2ojKASDaiMoBSlYKSEdyb3VwMTIgcGN0OjFjIHN0YWJsZTpwcDEgdXNlX2NhY2hlYWJsZV9udHA6MSBlc3B2OjIxMCBzdXBwcmVzc19vbl9zcnA6MRABGKiIygEgqIjKAUpWCkhHcm91cDEzIHBjdDoxZCBzdGFibGU6cHAxIHVzZV9jYWNoZWFibGVfbnRwOjEgZXNwdjoyMTAgc3VwcHJlc3Nfb25fc3JwOjEQARipiMoBIKmIygFKVgpIR3JvdXAxNCBwY3Q6MWUgc3RhYmxlOnBwMSB1c2VfY2FjaGVhYmxlX250cDoxIGVzcHY6MjEwIHN1cHByZXNzX29uX3NycDoxEAEYqojKASCqiMoBSlYKSEdyb3VwMTUgcGN0OjFmIHN0YWJsZTpwcDEgdXNlX2NhY2hlYWJsZV9udHA6MSBlc3B2OjIxMCBzdXBwcmVzc19vbl9zcnA6MRABGKuIygEgq4jKAUpWCkhHcm91cDE2IHBjdDoxZyBzdGFibGU6cHAxIHVzZV9jYWNoZWFibGVfbnRwOjEgZXNwdjoyMTAgc3VwcHJlc3Nfb25fc3JwOjEQARisiMoBIKyIygFKVgpIR3JvdXAxNyBwY3Q6MWggc3RhYmxlOnBwMSB1c2VfY2FjaGVhYmxlX250cDoxIGVzcHY6MjEwIHN1cHByZXNzX29uX3NycDoxEAEYrYjKASCtiMoBSlYKSEdyb3VwMTggcGN0OjFpIHN0YWJsZTpwcDEgdXNlX2NhY2hlYWJsZV9udHA6MSBlc3B2OjIxMCBzdXBwcmVzc19vbl9zcnA6MRABGK6IygEgrojKAUpWCkhHcm91cDE5IHBjdDoxaiBzdGFibGU6cHAxIHVzZV9jYWNoZWFibGVfbnRwOjEgZXNwdjoyMTAgc3VwcHJlc3Nfb25fc3JwOjEQARiviMoBIK+IygFKQgoRR3JvdXAyMCBzdGFibGU6ZjEQACorZW5hYmxlLW9yaWdpbi1jaGlwLXYyLWhpZGUtb24tbW91c2UtcmVsZWFzZUo/ChFHcm91cDIxIHN0YWJsZTpmMRAAKihlbmFibGUtb3JpZ2luLWNoaXAtdjItaGlkZS1vbi11c2VyLWlucHV0ShAKDERlZmF1bHRHcm91cBAAUg4SBDMzLiogAygAKAMoAVivusqaARJOChZFbmZvcmNlU2lnbmluVG9Vc2VBcHBzGMSlnLQFOAFCB0VuYWJsZWRKDAoIRGlzYWJsZWQQAEoLCgdFbmFibGVkEGRSCCAAIAEoACgBEuUDChFFbmhhbmNlZEJvb2ttYXJrcxiA2qmcBTgBQgdEZWZhdWx0SpMBCg9FeHRlbnNpb24gKG9sZCkQADIZChRlbmFibGUtZG9tLWRpc3RpbGxlchIBMTIgChtlbmFibGUtb3ZlcnJpZGUtYm9va21hcmstdWkSATEyGQoUZW5hYmxlLXN5bmMtYXJ0aWNsZXMSATEyJgoCaWQSIGdtbGxsYmdobmZrcGZsZW1paGxqZWtiYXBqb3BmamlrSpMBCg9FeHRlbnNpb24gKG5ldykQADIZChRlbmFibGUtZG9tLWRpc3RpbGxlchIBMTIgChtlbmFibGUtb3ZlcnJpZGUtYm9va21hcmstdWkSATEyGQoUZW5hYmxlLXN5bmMtYXJ0aWNsZXMSATEyJgoCaWQSIG1lb2Vlb2FvaGJtZ2JvY3BkcG5qa2xtZm1qamFna2tmSi0KDk1hbnVhbCBpbnN0YWxsEAAqGW1hbnVhbC1lbmhhbmNlZC1ib29rbWFya3NKQwodTWFudWFsIGluc3RhbGwgKHVzZXIgb3B0LW91dCkQACogbWFudWFsLWVuaGFuY2VkLWJvb2ttYXJrcy1vcHRvdXRKCwoHRGVmYXVsdBBkUhISBDMzLiogASAAKAAoAygBKAISpgIKGUV4dGVuc2lvblBlcm1pc3Npb25EaWFsb2cYwMqPpQU4AUIHR3JvdXBfMEoQCgdHcm91cF8xEAEYtJPKAUoQCgdHcm91cF8yEAEYtZPKAUoQCgdHcm91cF8zEAEYtpPKAUoQCgdHcm91cF80EAEYt5PKAUoQCgdHcm91cF81EAEYuJPKAUoQCgdHcm91cF82EAEYuZPKAUoQCgdHcm91cF83EAEYupPKAUoQCgdHcm91cF84EAEYu5PKAUoQCgdHcm91cF85EAEYvJPKAUoRCghHcm91cF8xMBABGL2TygFKEQoIR3JvdXBfMTEQARi+k8oBShEKCEdyb3VwXzEyEAEYv5PKAUoRCgdHcm91cF8wELwBGLOTygFSChIEMzQuKiADKAASpwIKGUV4dGVuc2lvblBlcm1pc3Npb25EaWFsb2cYwMqPpQU4AUIHR3JvdXBfMEoQCgdHcm91cF8xEA8YtJPKAUoQCgdHcm91cF8yEA8YtZPKAUoQCgdHcm91cF8zEA8YtpPKAUoQCgdHcm91cF80EA8Yt5PKAUoQCgdHcm91cF81EA8YuJPKAUoQCgdHcm91cF82EA8YuZPKAUoQCgdHcm91cF83EA8YupPKAUoQCgdHcm91cF84EA8Yu5PKAUoQCgdHcm91cF85EA8YvJPKAUoRCghHcm91cF8xMBAPGL2TygFKEQoIR3JvdXBfMTEQDxi+k8oBShEKCEdyb3VwXzEyEA8Yv5PKAUoQCgdHcm91cF8wEBQYs5PKAVIMEgQzNC4qIAAgASgAEkwKHEV4dGVuc2lvbkluc3RhbGxWZXJpZmljYXRpb24YxIH0owU4AUIETm9uZUoICgROb25lEGRSFBIEMzMuKiAAIAEgAiADKAEoAygCEnMKHEV4dGVuc2lvbkluc3RhbGxWZXJpZmljYXRpb24YxIH0owU4AUIETm9uZUoLCgdFbmZvcmNlEGRKDQoJQm9vdHN0cmFwEABKCwoHQ29udHJvbBAASggKBE5vbmUQAFISEgwzMy4wLjE3NTAuOTIgAigAEoEBChxFeHRlbnNpb25JbnN0YWxsVmVyaWZpY2F0aW9uGMSB9KMFOAFCBE5vbmVKCwoHRW5mb3JjZRAoSg0KCUJvb3RzdHJhcBAKSgsKB0NvbnRyb2wQKEoICgROb25lEApSIBIMMzMuMC4xNzUwLjE4GgwzMy4wLjE3NTAuOTEgAigAEnUKHEV4dGVuc2lvbkluc3RhbGxWZXJpZmljYXRpb24YxIH0owU4AUIETm9uZUoLCgdFbmZvcmNlEABKDQoJQm9vdHN0cmFwEDxKCwoHQ29udHJvbBAASggKBE5vbmUQKFIUEgwzMy4wLjE3NTAuMTggACABKAAScwocRXh0ZW5zaW9uSW5zdGFsbFZlcmlmaWNhdGlvbhjEgfSjBTgBQgROb25lSgsKB0VuZm9yY2UQAEoNCglCb290c3RyYXAQAUoLCgdDb250cm9sEAFKCAoETm9uZRBiUhISDDMzLjAuMTc1MC4xOCADKAASXAoYRmxhc2hIYXJkd2FyZVZpZGVvRGVjb2RlGMS33pwFOAFCCERpc2FibGVkSgwKB0h3VmlkZW8Q9ANKDAoHQ29udHJvbBD0A0oMCghEaXNhYmxlZBAAUgQgAigAEl4KGEZsYXNoSGFyZHdhcmVWaWRlb0RlY29kZRjEt96cBTgBQghEaXNhYmxlZEoMCgdId1ZpZGVvEPQDSgwKB0NvbnRyb2wQ9ANKDAoIRGlzYWJsZWQQAFIGIAAgASgAElcKFEZvcmNlQ29tcG9zaXRpbmdNb2RlGIC3pJwFOAFCB2Rpc2FibGVKCwoHZGlzYWJsZRBkSgsKB2VuYWJsZWQQAEoKCgZ0aHJlYWQQAFIIEgQyNC4qKAISVgoURm9yY2VDb21wb3NpdGluZ01vZGUYgLeknAU4AUIGdGhyZWFkSgsKB2Rpc2FibGUQAEoLCgdlbmFibGVkEABKCgoGdGhyZWFkEGRSCBIEMjguKigBElYKFEZvcmNlQ29tcG9zaXRpbmdNb2RlGIC3pJwFOAFCBnRocmVhZEoLCgdkaXNhYmxlEABKCwoHZW5hYmxlZBAASgoKBnRocmVhZBBkUggSBDI0LiooABI5Cg5Gb3JtRmFjdG9yVGVzdBjE1Z6VBTgBQgVQaG9uZUoKCgVQaG9uZRDoB1IKIAAgASgFKAQ4AWABEjsKDkZvcm1GYWN0b3JUZXN0GMTVnpUFOAFCBlRhYmxldEoLCgZUYWJsZXQQ6AdSCiAAIAEoBSgEOAJgARL+AQoJR29vZ2xlTm93OAFCB0RlZmF1bHRKCgoGRW5hYmxlEEZKNAoSRW5hYmxlTm9CYWNrZ3JvdW5kEA8yHAoTY2FuRW5hYmxlQmFja2dyb3VuZBIFZmFsc2VKCwoHQ29udHJvbBAPSgsKB0RlZmF1bHQQAEozCg9EaXNhYmxlZFZpYUZsYWcQACoeZGlzYWJsZS1nb29nbGUtbm93LWludGVncmF0aW9uSjEKDkVuYWJsZWRWaWFGbGFnEAAqHWVuYWJsZS1nb29nbGUtbm93LWludGVncmF0aW9uUhwSCzMzLjAuMTc1MC4qIAIoACgBKAMyBWVuLVVTWPPS4dQHEogCCglHb29nbGVOb3cYxJuSpQU4AUIHRGVmYXVsdEoKCgZFbmFibGUQZEo0ChJFbmFibGVOb0JhY2tncm91bmQQADIcChNjYW5FbmFibGVCYWNrZ3JvdW5kEgVmYWxzZUoLCgdDb250cm9sEABKCwoHRGVmYXVsdBAASjMKD0Rpc2FibGVkVmlhRmxhZxAAKh5kaXNhYmxlLWdvb2dsZS1ub3ctaW50ZWdyYXRpb25KMQoORW5hYmxlZFZpYUZsYWcQACodZW5hYmxlLWdvb2dsZS1ub3ctaW50ZWdyYXRpb25SIBILMzQuMC4xNzk3LiogACABKAAoASgDKAIyBWVuLVVTWPPS4dQHEqsCCglHb29nbGVOb3cYxJuSpQU4AUIHRGVmYXVsdEoKCgZFbmFibGUQGUo0ChJFbmFibGVOb0JhY2tncm91bmQQADIcChNjYW5FbmFibGVCYWNrZ3JvdW5kEgVmYWxzZUoLCgdDb250cm9sEABKCwoHRGVmYXVsdBBLSjMKD0Rpc2FibGVkVmlhRmxhZxAAKh5kaXNhYmxlLWdvb2dsZS1ub3ctaW50ZWdyYXRpb25KMQoORW5hYmxlZFZpYUZsYWcQACodZW5hYmxlLWdvb2dsZS1ub3ctaW50ZWdyYXRpb25SQxIEMzQuKiAAIAEgAigAKAEoAzIFZW4tR0IyAmZyMgJpdDICZGUyAmVzMgV6aC1DTjIFemgtVFcyAmphMgJrbzICcnVY89Lh1AcSiwEKDUhvc3RDYWNoZVNpemUYxM2IhwU4AEIHRGVmYXVsdEoLCgdEZWZhdWx0EABKCAoEMTAwQRAKSggKBDEwMEIQCkoICgQzMDBBEApKCAoEMzAwQhAKSgkKBTEwMDBBEApKCQoFMTAwMEIQCkoJCgUzMDAwQRAKSgkKBTMwMDBCEApSCBIEMjUuKigDEpMBCg1Ib3N0Q2FjaGVTaXplGMSs94cFOABCB0RlZmF1bHRKCwoHRGVmYXVsdBAASggKBDEwMEEQCkoICgQxMDBCEApKCAoEMzAwQRAKSggKBDMwMEIQCkoJCgUxMDAwQRAKSgkKBTEwMDBCEApKCQoFMzAwMEEQCkoJCgUzMDAwQhAKUhASBDI1LiogACABKAAoASgCEpECCg5JT1NQaG9uZU5ld05UUBjEtoGXBTgBQghEaXNhYmxlZEoTCglFbmFibGVkVjEQ6AcYr5PKAUoSCglDb250cm9sVjEQABiwk8oBShIKCUVuYWJsZWRWMhAAGLGTygFKEgoJQ29udHJvbFYyEAAYspPKAUorChBGb3JjZWRfRW5hYmxlZFYxEAAqFWVuYWJsZS1pb3MtbmV3LW50cC12MUorChBGb3JjZWRfRW5hYmxlZFYyEAAqFWVuYWJsZS1pb3MtbmV3LW50cC12MkooCg9Gb3JjZWRfRGlzYWJsZWQQACoTZGlzYWJsZS1pb3MtbmV3LW50cEoMCghEaXNhYmxlZBAAUgoSBDMyLiogAygFEpkCCg5JT1NQaG9uZU5ld05UUBjEm5KlBTgBQghEaXNhYmxlZEoTCglFbmFibGVkVjEQyAEYr5PKAUoTCglDb250cm9sVjEQyAEYsJPKAUoTCglFbmFibGVkVjIQyAEYsZPKAUoTCglDb250cm9sVjIQyAEYspPKAUorChBGb3JjZWRfRW5hYmxlZFYxEAAqFWVuYWJsZS1pb3MtbmV3LW50cC12MUorChBGb3JjZWRfRW5hYmxlZFYyEAAqFWVuYWJsZS1pb3MtbmV3LW50cC12MkooCg9Gb3JjZWRfRGlzYWJsZWQQACoTZGlzYWJsZS1pb3MtbmV3LW50cEoNCghEaXNhYmxlZBDIAVIOEgQzMi4qIAAgASACKAUSoQIKDklPU1Bob25lTmV3TlRQGMSbkqUFOAFCCERpc2FibGVkShcKDkVuYWJsZWRPbW5pYm94EDIY8pPKAUoXCg5Db250cm9sT21uaWJveBAyGPOTygFKEgoJRW5hYmxlZFYyEDIY9JPKAUoSCglDb250cm9sVjIQMhj1k8oBSisKEEZvcmNlZF9FbmFibGVkVjEQACoVZW5hYmxlLWlvcy1uZXctbnRwLXYxSisKEEZvcmNlZF9FbmFibGVkVjIQACoVZW5hYmxlLWlvcy1uZXctbnRwLXYySigKD0ZvcmNlZF9EaXNhYmxlZBAAKhNkaXNhYmxlLWlvcy1uZXctbnRwSg0KCERpc2FibGVkEKAGUgoSBDMzLiogAygFWJ7vtMULEnQKGklPU1N0b3BMb2FkT25BcHBCYWNrZ3JvdW5kGMSC6JkFOAFCB0RlZmF1bHRKGgoWRW5hYmxlZFJlbG9hZEZyb250bW9zdBAySgwKCERpc2FibGVkEDJKCwoHRGVmYXVsdBAAUg4SBDMyLiogACABIAIoBRJwChpJT1NTdG9wTG9hZE9uQXBwQmFja2dyb3VuZBjEguiZBTgBQgdEZWZhdWx0ShoKFkVuYWJsZWRSZWxvYWRGcm9udG1vc3QQBUoMCghEaXNhYmxlZBAFSgsKB0RlZmF1bHQQWlIKEgQzMi4qIAMoBRKaAgoPSU9TVGFibGV0TmV3TlRQGMSbkqUFOAFCCERpc2FibGVkShMKCUVuYWJsZWRWMRDIARjok8oBShMKCUNvbnRyb2xWMRDIARjpk8oBShMKCUVuYWJsZWRWMhDIARjqk8oBShMKCUNvbnRyb2xWMhDIARjrk8oBSisKEEZvcmNlZF9FbmFibGVkVjEQACoVZW5hYmxlLWlvcy1uZXctbnRwLXYxSisKEEZvcmNlZF9FbmFibGVkVjIQACoVZW5hYmxlLWlvcy1uZXctbnRwLXYySigKD0ZvcmNlZF9EaXNhYmxlZBAAKhNkaXNhYmxlLWlvcy1uZXctbnRwSg0KCERpc2FibGVkEMgBUg4SBDMzLiogACABIAIoBRKcAgoPSU9TVGFibGV0TmV3TlRQGMSbkqUFOAFCCERpc2FibGVkShcKDkVuYWJsZWRPbW5pYm94EDIY7JPKAUoXCg5Db250cm9sT21uaWJveBAyGO2TygFKEgoJRW5hYmxlZFYyEDIY7pPKAUoSCglDb250cm9sVjIQMhjvk8oBSisKEEZvcmNlZF9FbmFibGVkVjEQACoVZW5hYmxlLWlvcy1uZXctbnRwLXYxSisKEEZvcmNlZF9FbmFibGVkVjIQACoVZW5hYmxlLWlvcy1uZXctbnRwLXYySigKD0ZvcmNlZF9EaXNhYmxlZBAAKhNkaXNhYmxlLWlvcy1uZXctbnRwSg0KCERpc2FibGVkEKAGUgoSBDMzLiogAygFEpMBCh1JT1NVUkxDb250aW51b3VzQ2hlY2tJbnRlcnZhbBjEj7eaBTgAQgdEZWZhdWx0ShcKE0NoZWNrSW50ZXJ2YWxNUzYwMDAQCkoXChNDaGVja0ludGVydmFsTVM5MDAwEApKGAoUQ2hlY2tJbnRlcnZhbERlZmF1bHQQCkoLCgdEZWZhdWx0EEZSCCAAIAEgAigFEpYBCh1JT1NVUkxDb250aW51b3VzQ2hlY2tJbnRlcnZhbBjEj7eaBTgAQgdEZWZhdWx0ShcKE0NoZWNrSW50ZXJ2YWxNUzYwMDAQAUoXChNDaGVja0ludGVydmFsTVM5MDAwEAFKGAoUQ2hlY2tJbnRlcnZhbERlZmF1bHQQAUoMCgdEZWZhdWx0EOUHUgoSBDMzLiogAygFEkQKDUluZmluaXRlQ2FjaGUYxLSNlgU4AUICTm9KBwoCTm8Q1AdKBwoDWWVzEApKCwoHQ29udHJvbBAKUgggAigAKAEoAhJGCg1JbmZpbml0ZUNhY2hlGMS0jZYFOAFCAk5vSgcKAk5vEIQHSgcKA1llcxAySgsKB0NvbnRyb2wQMlIKIAAgASgAKAEoAhJECg1JbmZpbml0ZUNhY2hlGMS0jZYFOAFCAk5vSgcKAk5vEOYHSgcKA1llcxABSgsKB0NvbnRyb2wQAVIIIAMoACgBKAIS3wQKDEluc3RhbnREdW1teRiAhNyPBTgBQgxEZWZhdWx0R3JvdXBKLwohRHVtbXlHcm91cDEgY2hhbm5lbDpzdGFibGUgbW9kczoxEAEYx4XKASDHhcoBSi8KIUR1bW15R3JvdXAyIGNoYW5uZWw6c3RhYmxlIG1vZHM6MRABGMiFygEgyIXKAUovCiFEdW1teUdyb3VwMyBjaGFubmVsOnN0YWJsZSBtb2RzOjEQARjJhcoBIMmFygFKLwohRHVtbXlHcm91cDQgY2hhbm5lbDpzdGFibGUgbW9kczoxEAEYyoXKASDKhcoBSi8KIUR1bW15R3JvdXA1IGNoYW5uZWw6c3RhYmxlIG1vZHM6ORAJGMuFygEgy4XKAUovCiFEdW1teUdyb3VwNiBjaGFubmVsOnN0YWJsZSBtb2RzOjkQCRjMhcoBIMyFygFKLwohRHVtbXlHcm91cDcgY2hhbm5lbDpzdGFibGUgbW9kczo5EAkYzYXKASDNhcoBSi8KIUR1bW15R3JvdXA4IGNoYW5uZWw6c3RhYmxlIG1vZHM6ORAJGM6FygEgzoXKAUoxCiNEdW1teUdyb3VwOSBjaGFubmVsOnN0YWJsZSBtb2RzOjEwMBBkGM+FygEgz4XKAUoyCiREdW1teUdyb3VwMTAgY2hhbm5lbDpzdGFibGUgbW9kczoxMDAQZBjQhcoBINCFygFKKgobRHVtbXlQYWRkaW5nIGNoYW5uZWw6c3RhYmxlEPgFGNGFygEg0YXKAUoQCgxEZWZhdWx0R3JvdXAQAFIMEgQyNy4qIAMoACgBEp8OCg9JbnN0YW50RXh0ZW5kZWQYgPfSmQU4AUIMRGVmYXVsdEdyb3VwSlwKTkdyb3VwMjAgcGN0OjUgc3RhYmxlOnI0IHVzZV9yZW1vdGVfbnRwX29uX3N0YXJ0dXA6MSBlc3B2OjIxMCBzdXBwcmVzc19vbl9zcnA6MRAFGISIygEghIjKAUpcCk5Hcm91cDEgcGN0OjI1IHN0YWJsZTpyNCB1c2VfcmVtb3RlX250cF9vbl9zdGFydHVwOjEgZXNwdjoyMTAgc3VwcHJlc3Nfb25fc3JwOjEQGRiFiMoBIIWIygFKXQpPR3JvdXAyIHBjdDoxMGEgc3RhYmxlOnI1IHVzZV9yZW1vdGVfbnRwX29uX3N0YXJ0dXA6MSBlc3B2OjIxMCBzdXBwcmVzc19vbl9zcnA6MRAKGIaIygEghojKAUpdCk9Hcm91cDMgcGN0OjEwYiBzdGFibGU6cjcgdXNlX3JlbW90ZV9udHBfb25fc3RhcnR1cDoxIGVzcHY6MjEwIHN1cHByZXNzX29uX3NycDoxEAoYkojKASCSiMoBSnEKY0dyb3VwNCBwY3Q6MTBjIHN0YWJsZTpyNyB1c2VfY2FjaGVhYmxlX250cDoxIHVzZV9yZW1vdGVfbnRwX29uX3N0YXJ0dXA6MSBlc3B2OjIxMCBzdXBwcmVzc19vbl9zcnA6MRAKGJOIygEgk4jKAUpeClBHcm91cDUgcGN0OjEwZCBzdGFibGU6cHAzIHVzZV9yZW1vdGVfbnRwX29uX3N0YXJ0dXA6MSBlc3B2OjIxMCBzdXBwcmVzc19vbl9zcnA6MRAKGJSIygEglIjKAUpeClBHcm91cDYgcGN0OjEwZSBzdGFibGU6cHAxIHVzZV9yZW1vdGVfbnRwX29uX3N0YXJ0dXA6MSBlc3B2OjIxMCBzdXBwcmVzc19vbl9zcnA6MRAKGNyHygEg3IfKAUpeClBHcm91cDcgcGN0OjEwZiBzdGFibGU6cHAxIHVzZV9yZW1vdGVfbnRwX29uX3N0YXJ0dXA6MSBlc3B2OjIxMCBzdXBwcmVzc19vbl9zcnA6MRAKGN2HygEg3YfKAUpwCmJHcm91cDggcGN0OjFhIHN0YWJsZTpyNSB1c2VfY2FjaGVhYmxlX250cDoxIHVzZV9yZW1vdGVfbnRwX29uX3N0YXJ0dXA6MSBlc3B2OjIxMCBzdXBwcmVzc19vbl9zcnA6MRABGIeIygEgh4jKAUpdCk9Hcm91cDkgcGN0OjFiIHN0YWJsZTpwcDIgdXNlX3JlbW90ZV9udHBfb25fc3RhcnR1cDoxIGVzcHY6MjEwIHN1cHByZXNzX29uX3NycDoxEAEYgojKASCCiMoBSl4KUEdyb3VwMTAgcGN0OjFjIHN0YWJsZTpwcDIgdXNlX3JlbW90ZV9udHBfb25fc3RhcnR1cDoxIGVzcHY6MjEwIHN1cHByZXNzX29uX3NycDoxEAEYg4jKASCDiMoBSl4KUEdyb3VwMTEgcGN0OjFkIHN0YWJsZTpwcDMgdXNlX3JlbW90ZV9udHBfb25fc3RhcnR1cDoxIGVzcHY6MjEwIHN1cHByZXNzX29uX3NycDoxEAEYlYjKASCViMoBSl4KUEdyb3VwMTIgcGN0OjFlIHN0YWJsZTpwcDEgdXNlX3JlbW90ZV9udHBfb25fc3RhcnR1cDoxIGVzcHY6MjEwIHN1cHByZXNzX29uX3NycDoxEAEY4ofKASDih8oBSl4KUEdyb3VwMTMgcGN0OjFmIHN0YWJsZTpwcDEgdXNlX3JlbW90ZV9udHBfb25fc3RhcnR1cDoxIGVzcHY6MjEwIHN1cHByZXNzX29uX3NycDoxEAEY44fKASDjh8oBSl4KUEdyb3VwMTQgcGN0OjFnIHN0YWJsZTpwcDEgdXNlX3JlbW90ZV9udHBfb25fc3RhcnR1cDoxIGVzcHY6MjEwIHN1cHByZXNzX29uX3NycDoxEAEY5IfKASDkh8oBSl0KT0dyb3VwMTUgcGN0OjFoIHN0YWJsZTpyMyB1c2VfcmVtb3RlX250cF9vbl9zdGFydHVwOjEgZXNwdjoyMTAgc3VwcHJlc3Nfb25fc3JwOjEQARiAiMoBIICIygFKSwo9R3JvdXAxNiBwY3Q6MWkgc3RhYmxlOnIzIHVzZV9yZW1vdGVfbnRwX29uX3N0YXJ0dXA6MSBlc3B2OjIxNRABGIGIygEggYjKAUpeClBHcm91cDE3IHBjdDoxaiBzdGFibGU6cHAxIHVzZV9yZW1vdGVfbnRwX29uX3N0YXJ0dXA6MSBlc3B2OjIxMCBzdXBwcmVzc19vbl9zcnA6MRABGOeHygEg54fKAUoQCgxEZWZhdWx0R3JvdXAQAFIUEgQzMC4qGgQzMS4qIAMoACgDKAFYvt/3rAUSlAIKFkludGVyc3RpdGlhbE1hbHdhcmUzMTAYwJekkwU4AUIHRGVmYXVsdEoXChNjb25kMU1hbHdhcmVDb250cm9sEANKFwoTY29uZDJNYWx3YXJlTm9CcmFuZBADShcKE2NvbmQ1TWFsd2FyZU9uZVN0ZXAQA0oXChNjb25kN01hbHdhcmVGZWFyTXNnEANKGQoVY29uZDlNYWx3YXJlQ29sbGFiTXNnEANKGQoVY29uZDExTWFsd2FyZVF1ZXN0aW9uEANKFwoTY29uZDEzTWFsd2FyZUdvQmFjaxADSgwKB0RlZmF1bHQQswFSKAjA2aOMBRIEMjkuKhoEMzIuKigAKAEoAigDMgVlbi1VUzIFZW4tR0ISnQIKF0ludGVyc3RpdGlhbFBoaXNoaW5nNTY0GMCXpJMFOAFCB0RlZmF1bHRKGAoUY29uZDNQaGlzaGluZ0NvbnRyb2wQA0oYChRjb25kNFBoaXNoaW5nTm9CcmFuZBADShgKFGNvbmQ2UGhpc2hpbmdPbmVTdGVwEANKGAoUY29uZDhQaGlzaGluZ0ZlYXJNc2cQA0obChdjb25kMTBQaGlzaGluZ0NvbGxhYk1zZxADShoKFmNvbmQxMlBoaXNoaW5nUXVlc3Rpb24QA0oYChRjb25kMTRQaGlzaGluZ0dvQmFjaxADSgwKB0RlZmF1bHQQswFSKAjA2aOMBRIEMjkuKhoEMzIuKigAKAEoAigDMgVlbi1VUzIFZW4tR0ISqgIKEkludGVyc3RpdGlhbFNTTDUxNxjAnpeRBTgBQgdEZWZhdWx0ShkKFUNvbmRpdGlvbjE1U1NMQ29udHJvbBADShkKFUNvbmRpdGlvbjE2U1NMRmlyZWZveBADSh4KGkNvbmRpdGlvbjE3U1NMRmFuY3lGaXJlZm94EANKGgoWQ29uZGl0aW9uMThTU0xOb0ltYWdlcxADShsKF0NvbmRpdGlvbjE5U1NMUG9saWNlbWFuEANKGwoXQ29uZGl0aW9uMjBTU0xTdG9wbGlnaHQQA0oYChRDb25kaXRpb24yMVNTTEJhZGd1eRADSgwKB0RlZmF1bHQQswFSLwjA2aOMBRILMjkuMC4xNTQzLioaBDMwLiooACgBKAIoAzIFZW4tVVMyBWVuLUdCElgKGUxhdW5jaGVyVXNlV2Vic3RvcmVTZWFyY2gYxJuSpQU4AUIGRW5hYmxlSgoKBkVuYWJsZRBkSgsKB0Rpc2FibGUQAFISEgwyOS4wLjE1NDcuMzIoACgDEtgCChZNYWx3YXJlRG93bmxvYWRXYXJuaW5nGMToppMFOAFCB0RlZmF1bHRKFQoRQ29uZGl0aW9uMUNvbnRyb2wQAUoVChFDb25kaXRpb24yQ29udHJvbBABShcKE0NvbmRpdGlvbjNNYWxpY2lvdXMQAUoUChBDb25kaXRpb240VW5zYWZlEAFKFwoTQ29uZGl0aW9uNURhbmdlcm91cxABShUKEUNvbmRpdGlvbjZIYXJtZnVsEAFKGwoXQ29uZGl0aW9uN0Rpc2NhcmRTZWNvbmQQAUoaChZDb25kaXRpb244RGlzY2FyZEZpcnN0EAFKGQoVQ29uZGl0aW9uOVNhZmVEaXNjYXJkEAFKGgoWQ29uZGl0aW9uMTBTYWZlRG9udFJ1bhABSgsKB0RlZmF1bHQQWlIjCMSSn5EFEgQzMC4qGgQzMi4qIAAgASACIAMoADIFZW4tVVMSUQoRTWFuYWdlZE1vZGVMYXVuY2gYgNqpnAU4AUIISW5hY3RpdmVKCgoGQWN0aXZlEGRKDAoISW5hY3RpdmUQAFIQEgQzMC4qIAAgASgAKAEoAhJNChFNYW5hZ2VkTW9kZUxhdW5jaBiA2qmcBTgBQghJbmFjdGl2ZUoKCgZBY3RpdmUQZEoMCghJbmFjdGl2ZRAAUgwSBDMwLiogACABKAMSUQoRTWFuYWdlZE1vZGVMYXVuY2gYgNqpnAU4AUIISW5hY3RpdmVKCgoGQWN0aXZlEGRKDAoISW5hY3RpdmUQAFIQEgQzMS4qIAIoACgBKAIoAxJWChFNYW5hZ2VkTW9kZUxhdW5jaBiA7o6gBTgBQghJbmFjdGl2ZUoKCgZBY3RpdmUQZEoMCghJbmFjdGl2ZRAAUhASBDMyLiogAygAKAEoAigDWKarvBgSWwofTWVkaWFTdHJlYW1BdWRpb1RyYWNrUHJvY2Vzc2luZxjE88edBTgBQgdFbmFibGVkSgwKCERpc2FibGVkEABKCwoHRW5hYmxlZBBkUgwgACgAKAEoAygCKAQSkgIKGE1vc3RWaXNpdGVkVGlsZVBsYWNlbWVudBiA/qKSBTgBQgdEZWZhdWx0ShYKEk9uZUVpZ2h0X0FfRmxpcHBlZBADSg4KCk9uZUVpZ2h0X0IQA0oWChJPbmVFaWdodF9DX0ZsaXBwZWQQA0oOCgpPbmVFaWdodF9EEANKFQoRT25lRm91cl9BX0ZsaXBwZWQQA0oNCglPbmVGb3VyX0IQA0oVChFPbmVGb3VyX0NfRmxpcHBlZBADSg0KCU9uZUZvdXJfRBADSgsKB0NvbnRyb2wQA0oUChBEb250U2hvd09wZW5UYWJzEANKCwoHRGVmYXVsdBBGUhkSCzI4LjAuMTQ5Ni4wIAEgACgAKAEoAigDEpIBChRNb3VzZUV2ZW50UHJlY29ubmVjdBjEtI2WBTgAQghEaXNhYmxlZEoNCglNb3VzZURvd24QHkoNCglNb3VzZU92ZXIQAEoSCg5UYXBVbmNvbmZpcm1lZBAASgsKB1RhcERvd24QAEoLCgdDb250cm9sEB5KDAoIRGlzYWJsZWQQKFIOEgQyOS4qIAIoACgBKAISmAEKFE1vdXNlRXZlbnRQcmVjb25uZWN0GMS0jZYFOABCCERpc2FibGVkSg0KCU1vdXNlRG93bhAKSg0KCU1vdXNlT3ZlchAAShIKDlRhcFVuY29uZmlybWVkEABKCwoHVGFwRG93bhAASgsKB0NvbnRyb2wQCkoMCghEaXNhYmxlZBBQUhQSBDI5LiogACABKAAoASgCKAMoBBK2AQoPTW9iaWxlTmF0aXZlTlRQGIDE0JcFOAFCEUxlZ2FjeU5UUENvbnRyb2wwShoKEUxlZ2FjeU5UUENvbnRyb2wxEBkYspLKAUogChdOYXRpdmVOVFBXaXRoVHdvVXJsQmFycxAZGLOSygFKIgoZTmF0aXZlTlRQV2l0aFNpbmdsZVVybEJhchAZGLSSygFKGgoRTGVnYWN5TlRQQ29udHJvbDAQGRixksoBUgoSBDMxLiogAigEEqQBCg9Nb2JpbGVOYXRpdmVOVFAYgMTQlwU4AUIRTGVnYWN5TlRQQ29udHJvbDBKFQoRTGVnYWN5TlRQQ29udHJvbDEQBUobChdOYXRpdmVOVFBXaXRoVHdvVXJsQmFycxAtSh0KGU5hdGl2ZU5UUFdpdGhTaW5nbGVVcmxCYXIQLUoVChFMZWdhY3lOVFBDb250cm9sMBAFUgwSBDMxLiogACABKAQStwEKD01vYmlsZU5hdGl2ZU5UUBiAl6qYBTgBQhFMZWdhY3lOVFBDb250cm9sMEobChFMZWdhY3lOVFBDb250cm9sMRDhBhi4ksoBSiAKF05hdGl2ZU5UUFdpdGhUd29VcmxCYXJzEC0YuZLKAUoiChlOYXRpdmVOVFBXaXRoU2luZ2xlVXJsQmFyEC0YupLKAUoaChFMZWdhY3lOVFBDb250cm9sMBAtGLeSygFSChIEMzIuKiADKAQSfAoVTW9iaWxlVGFibGV0TmF0aXZlTlRQGIDE0JcFOAFCEExlZ2FjeU5UUENvbnRyb2xKIgoZTmF0aXZlTlRQV2l0aFNpbmdsZVVybEJhchAyGLaSygFKGQoQTGVnYWN5TlRQQ29udHJvbBAyGLWSygFSChIEMzIuKiACKAQSdAoVTW9iaWxlVGFibGV0TmF0aXZlTlRQGIDE0JcFOAFCEExlZ2FjeU5UUENvbnRyb2xKHQoZTmF0aXZlTlRQV2l0aFNpbmdsZVVybEJhchBfShQKEExlZ2FjeU5UUENvbnRyb2wQBVIMEgQzMS4qIAAgASgEEpoBChVNb2JpbGVUYWJsZXROYXRpdmVOVFAYgJeqmAU4AUIRTGVnYWN5TlRQQ29udHJvbDBKIgoZTmF0aXZlTlRQV2l0aFNpbmdsZVVybEJhchAJGLySygFKGgoRTGVnYWN5TlRQQ29udHJvbDEQUhi9ksoBShoKEUxlZ2FjeU5UUENvbnRyb2wwEAkYu5LKAVIKEgQzMi4qIAMoBBJdCgxOZXdNZW51U3R5bGUYgNCfjQU4AUIHRGVmYXVsdEoLCgdEZWZhdWx0EABKDQoITmV3U3R5bGUQ5gdKDAoIT2xkU3R5bGUQAlISEgQyNi4qGgQyNy4qIAMoACgDEn4KDE5ld01lbnVTdHlsZRiA/qKSBTgBQgdEZWZhdWx0SgsKB0RlZmF1bHQQAEoMCghDb21wYWN0MRAASgwKCENvbXBhY3QyEGRKEgoOSGlnaGVyQ29udHJhc3QQAEoQCgxDb250cm9sR3JvdXAQAFIOEgQyOC4qIAEgACgAKAMShAEKDE5ld01lbnVTdHlsZRiA74KWBTgBQgdEZWZhdWx0SgsKB0RlZmF1bHQQAEoMCghDb21wYWN0MRAASgwKCENvbXBhY3QyEGRKEgoOSGlnaGVyQ29udHJhc3QQAEoQCgxDb250cm9sR3JvdXAQAFIUEgQyOC4qGgQzMC4qIAMgAigAKAMSsAEKFE5ld1Byb2ZpbGVNYW5hZ2VtZW50GMSCl7QFOAFCB0NvbnRyb2xKNQoUQ29tbWFuZC1MaW5lLUVuYWJsZWQQABjIksoBKhZuZXctcHJvZmlsZS1tYW5hZ2VtZW50SgwKCERpc2FibGVkEABKEAoHRW5hYmxlZBAAGMiSygFKCwoHQ29udHJvbBAyUiEIxJS2lwUSCzM0LjAuMTc4Mi4yIAAgASgAKAEoAigEKAVgARJXCgxOZXdUYWJCdXR0b24YgLWNlgU4AUIHZGVmYXVsdEoLCgdkZWZhdWx0EGJKCwoHQ29udHJvbBABSggKBFBsdXMQAVISEgwyMS4wLjExODAuMTUgAygAEuEDChpPbW5pYm94QnVuZGxlZEV4cGVyaW1lbnRWMRiAnYabBTgBQhtCZXRhSFFQRXhwZXJpbWVudHNDb250cm9sUjJKnQEKL0JldGFSZW9kZXJIUVBBbmREaXNjb3VudEZyZWNlbmN5V2hlbkZld1Zpc2l0c1IyEAoyKAogSFFQRGlzY291bnRGcmVjZW5jeVdoZW5GZXdWaXNpdHMSBHRydWUyPgofUmVvcmRlckZvckxlZ2FsRGVmYXVsdE1hdGNoOio6KhIbUmVvcmRlckZvckxlZ2FsRGVmYXVsdE1hdGNoSjQKGEJldGFIUVBCb29rbWFya1ZhbHVlMTBSMhAKMhYKEEhRUEJvb2ttYXJrVmFsdWUSAjEwSjIKF0JldGFIUVBCb29rbWFya1ZhbHVlNVIyEAoyFQoQSFFQQm9va21hcmtWYWx1ZRIBNUpdChVCZXRhUmVvcmRlckhvbGRiYWNrUjIQCjJCCh9SZW9yZGVyRm9yTGVnYWxEZWZhdWx0TWF0Y2g6KjoqEh9Eb250UmVvcmRlckZvckxlZ2FsRGVmYXVsdE1hdGNoSh8KG0JldGFIUVBFeHBlcmltZW50c0NvbnRyb2xSMhA8Ug4IxICujgUSBDMzLiogAljO6qDxARL2BwoaT21uaWJveEJ1bmRsZWRFeHBlcmltZW50VjEYgJ2GmwU4AUIIU3RhbmRhcmRKNgoUU2VhcmNoSGlzdG9yeURpc2FibGUQADIcChFTZWFyY2hIaXN0b3J5Oio6KhIHRGlzYWJsZUofChtEZW1vdGVOYXZGYWtlYm94IFBPU1RQRVJJT0QQAUomCiJEZW1vdGVOYXZGYWtlYm94Q29udHJvbCBQT1NUUEVSSU9EEAFKKwonRGV2SFVQRXhwZXJpbWVudGFsU2NvcmluZ05vRGVjYXlDb250cm9sEApKyQEKIERldkhVUEV4cGVyaW1lbnRhbFNjb3JpbmdOb0RlY2F5EAoyIgodSFVQRXhwZXJpbWVudGFsU2NvcmluZ0VuYWJsZWQSATEyHAoWVHlwZWRDb3VudEhhbGZMaWZlVGltZRICLTEyLAoWVHlwZWRDb3VudFNjb3JlQnVja2V0cxISMC45NzoxMzYwLDAuMDoxMjgwMjMKGFZpc2l0ZWRDb3VudEhhbGZMaWZlVGltZRIXNC4wOjc5MCwwLjU6NTkwLDAuMDoxMDBKJAogRGV2SFVQRXhwZXJpbWVudGFsU2NvcmluZ0NvbnRyb2wQCkrCAQoZRGV2SFVQRXhwZXJpbWVudGFsU2NvcmluZxAKMiIKHUhVUEV4cGVyaW1lbnRhbFNjb3JpbmdFbmFibGVkEgExMhwKFlR5cGVkQ291bnRIYWxmTGlmZVRpbWUSAjMwMiwKFlR5cGVkQ291bnRTY29yZUJ1Y2tldHMSEjAuOTc6MTM2MCwwLjA6MTI4MDIzChhWaXNpdGVkQ291bnRIYWxmTGlmZVRpbWUSFzQuMDo3OTAsMC41OjU5MCwwLjA6MTAwSjYKMkRldlJlb3JkZXJBbmRIUVBTY29yaW5nU2hhcmVkQ29udHJvbCByNCBQT1NUUEVSSU9EEApKIAocRGVtb3RlTmF2RmFrZWJveDIgUE9TVFBFUklPRBAKSk4KSkRldkhRUFNjb3JpbmdBbGxvd01hdGNoSW5TY2hlbWVBbmREaXNjb3VudEZyZWNlbmN5V2hlbkZld1Zpc2l0cyBQT1NUUEVSSU9EEApKSwpHRGV2SFFQU2NvcmluZ0FsbG93TWF0Y2hJblRMREFuZERpc2NvdW50RnJlY2VuY3lXaGVuRmV3VmlzaXRzIFBPU1RQRVJJT0QQCko7CjdEZXZSZW9kZXJIUVBBbmREaXNjb3VudEZyZWNlbmN5V2hlbkZld1Zpc2l0cyBQT1NUUEVSSU9EEApKDAoIU3RhbmRhcmQQCFIfCMTFoZMFEgszMy4wLjE3MTEuKiAAIAEoACgBKAMoAhLFCwoaT21uaWJveEJ1bmRsZWRFeHBlcmltZW50VjEYgJ2GmwU4AUIFRW1wdHlKCQoFRW1wdHkQAEqmAQolUG9zdFBlcmlvZF9EZW1vdGVOYXZGYWtlYm94X1N0YWJsZV9SNBABGJOTygEgk5PKATItChBEZW1vdGVCeVR5cGU6ODoqEhkxOjYxLDI6NjEsMzo2MSw0OjYxLDEyOjYxMkIKH1Jlb3JkZXJGb3JMZWdhbERlZmF1bHRNYXRjaDoqOioSH0RvbnRSZW9yZGVyRm9yTGVnYWxEZWZhdWx0TWF0Y2hKrQEKLFBvc3RQZXJpb2RfRGVtb3RlTmF2RmFrZWJveENvbnRyb2xfU3RhYmxlX1I0EAEYlJPKASCUk8oBMi0KEERlbW90ZUJ5VHlwZTo4OioSGTE6NjEsMjo2MSwzOjYxLDQ6NjEsMTI6NjEyQgofUmVvcmRlckZvckxlZ2FsRGVmYXVsdE1hdGNoOio6KhIfRG9udFJlb3JkZXJGb3JMZWdhbERlZmF1bHRNYXRjaEqbAQoaUFBfT21uaWJveEdyb3VwQV9TdGFibGVfUjMQARj+ksoBIP6SygEyLQoQRGVtb3RlQnlUeXBlOjg6KhIZMTo2MSwyOjYxLDM6NjEsNDo2MSwxMjo2MTJCCh9SZW9yZGVyRm9yTGVnYWxEZWZhdWx0TWF0Y2g6KjoqEh9Eb250UmVvcmRlckZvckxlZ2FsRGVmYXVsdE1hdGNoSpsBChpQUF9PbW5pYm94R3JvdXBCX1N0YWJsZV9SMxABGP+SygEg/5LKATItChBEZW1vdGVCeVR5cGU6ODoqEhkxOjYxLDI6NjEsMzo2MSw0OjYxLDEyOjYxMkIKH1Jlb3JkZXJGb3JMZWdhbERlZmF1bHRNYXRjaDoqOioSH0RvbnRSZW9yZGVyRm9yTGVnYWxEZWZhdWx0TWF0Y2hKmwEKGlBQX09tbmlib3hHcm91cENfU3RhYmxlX1IzEAEYgJPKASCAk8oBMi0KEERlbW90ZUJ5VHlwZTo4OioSGTE6NjEsMjo2MSwzOjYxLDQ6NjEsMTI6NjEyQgofUmVvcmRlckZvckxlZ2FsRGVmYXVsdE1hdGNoOio6KhIfRG9udFJlb3JkZXJGb3JMZWdhbERlZmF1bHRNYXRjaEqbAQoaRGVtb3RlTmF2RmFrZWJveF9TdGFibGVfUjQQARiLk8oBIIuTygEyLQoQRGVtb3RlQnlUeXBlOjg6KhIZMTo2MSwyOjYxLDM6NjEsNDo2MSwxMjo2MTJCCh9SZW9yZGVyRm9yTGVnYWxEZWZhdWx0TWF0Y2g6KjoqEh9Eb250UmVvcmRlckZvckxlZ2FsRGVmYXVsdE1hdGNoSo4BCiFEZW1vdGVOYXZGYWtlYm94Q29udHJvbF9TdGFibGVfUjQQARiMk8oBIIyTygEyGQoQRGVtb3RlQnlUeXBlOjg6KhIFMToxMDAyQgofUmVvcmRlckZvckxlZ2FsRGVmYXVsdE1hdGNoOio6KhIfRG9udFJlb3JkZXJGb3JMZWdhbERlZmF1bHRNYXRjaEqOAQoXU3RhYmxlUmVvcmRlckhvbGRiYWNrUjIQCjItChBEZW1vdGVCeVR5cGU6ODoqEhkxOjYxLDI6NjEsMzo2MSw0OjYxLDEyOjYxMkIKH1Jlb3JkZXJGb3JMZWdhbERlZmF1bHRNYXRjaDoqOioSH0RvbnRSZW9yZGVyRm9yTGVnYWxEZWZhdWx0TWF0Y2hKgQEKClN0YW5kYXJkUjIQUzItChBEZW1vdGVCeVR5cGU6ODoqEhkxOjYxLDI6NjEsMzo2MSw0OjYxLDEyOjYxMkIKH1Jlb3JkZXJGb3JMZWdhbERlZmF1bHRNYXRjaDoqOioSH0RvbnRSZW9yZGVyRm9yTGVnYWxEZWZhdWx0TWF0Y2hSFgiAhP+UBRIEMzEuKiADKAAoASgDKAISzQEKHk9tbmlib3hSZXBsYWNlSFVQQW5kTmV3U2NvcmluZxjAhbOQBTgBQghTdGFuZGFyZEoMCghTdGFuZGFyZBA8Sg0KCVN0YW5kYXJkMhAKSh0KGUhRUC1wb3N0cGVyaW9kLVJlcGxhY2VIVVAQCkoOCgpOZXdTY29yaW5nEApKNAowSFFQLXBvc3RwZXJpb2QtUmVwbGFjZUhVUF9OZXctcG9zdHBlcmlvZC1TY29yaW5nEApSFwjAn4uHBRILMjguMC4xNDk5LiogASACEmQKFE9tbmlib3hTZWFyY2hIaXN0b3J5GMSQq5AFOAFCCFN0YW5kYXJkShMKD1ByZXZlbnRJbmxpbmluZxAKSgsKB0Rpc2FibGUQCkoMCghTdGFuZGFyZBBQUgoSBDMwLiogACABEm8KF09tbmlib3hTaG9ydGN1dHNTY29yaW5nGMTKiaAFOAFCCFN0YW5kYXJkSgwKCFN0YW5kYXJkEFpKFQoRTWF4UmVsZXZhbmNlXzEzOTkQClIdCMSAro4FEgsyOS4wLjE1NDcuMBoEMjkuKiABIAISZQoQT21uaWJveFN0b3BUaW1lchjA0ZmTBTgBQghTdGFuZGFyZEoSCghTdGFuZGFyZBD0Axi3hcoBShYKDFVzZVN0b3BUaW1lchD0Axi4hcoBUhMIwMzUiwUSCzI4LjAuMTQ4OC4wEmcKFE91dGRhdGVkSW5zdGFsbENoZWNrGMS0jZYFOAFCB0RlZmF1bHRKGgoWMTJXZWVrc091dGRhdGVkSW5zdGFsbBABSgsKB0RlZmF1bHQQAFIVEgsyNy4wLjE0NDcuMBoEMzAuKigAEq8BChJQYXNzd29yZEdlbmVyYXRpb24YxPPHnQU4AUIIRGlzYWJsZWRKCwoHRW5hYmxlZBAKSgwKCERpc2FibGVkEFpKLwoORGlzYWJsZWRCeUZsYWcQACobZGlzYWJsZS1wYXNzd29yZC1nZW5lcmF0aW9uSi0KDUVuYWJsZWRCeUZsYWcQACoaZW5hYmxlLXBhc3N3b3JkLWdlbmVyYXRpb25SDCAAIAEoACgBKAIoAxJGCghQcmVjYWNoZRjE6PiyBTgBQghEaXNhYmxlZEoLCgdFbmFibGVkEApKDQoIRGlzYWJsZWQQ3gdSDBIEMzQuKiAAIAEoBBKcAQoIUHJlZmV0Y2gYxJuSpQU4AUIHRGVmYXVsdEoWCg1FeHBlcmltZW50WWVzEAQY9pPKAUoXCg5FeHBlcmltZW50WWVzMhABGPeTygFKFgoNRXhwZXJpbWVudE5vMhABGPmTygFKFQoMRXhwZXJpbWVudE5vEAQY+JPKAUoLCgdEZWZhdWx0EFpSDBIEMzMuKiACIAAgAVii792IARKZAQoUUHJlcmVuZGVyRnJvbU9tbmlib3gYxLaknAU4AUIXT21uaWJveFByZXJlbmRlckVuYWJsZWRKGwoXT21uaWJveFByZXJlbmRlckVuYWJsZWQQAEocChhPbW5pYm94UHJlcmVuZGVyRGlzYWJsZWQQZFIlEgQzMS4qGgszNC4wLjE0ODIuMCAAIAEgAiADKAAoASgCKAMoBBJwChRQcmVyZW5kZXJGcm9tT21uaWJveBjEguiZBTgBQhhPbW5pYm94UHJlcmVuZGVyRGlzYWJsZWRKHAoYT21uaWJveFByZXJlbmRlckRpc2FibGVkEGRSGBIEMjkuKhoEMzAuKiADKAAoASgCKAMoBBJWChdQcmVyZW5kZXJMb2NhbFByZWRpY3RvchjEtI2WBTgAQghEaXNhYmxlZEoLCgdFbmFibGVkEGRKDAoIRGlzYWJsZWQQAFIOEgQyOS4qIAIoACgBKAISbAoXUHJlcmVuZGVyTG9jYWxQcmVkaWN0b3IYxIehjAU4AEIIRGlzYWJsZWRKDQoIRGlzYWJsZWQQ1AdKCwoHRW5hYmxlZBAKSgsKB0NvbnRyb2wQClIWEgQyNS4qGgQyOC4qIAMgAigAKAEoAhJmChdQcmVyZW5kZXJMb2NhbFByZWRpY3RvchjEtI2WBTgAQghEaXNhYmxlZEoMCghEaXNhYmxlZBBkSgwKB0VuYWJsZWQQoAZKCwoHQ29udHJvbBBkUhASBDI1LiogACABKAAoASgCElkKLlByZXJlbmRlckxvY2FsUHJlZGljdG9yTWF4Q29uY3VycmVudFByZXJlbmRlcnMYxLSNlgU4AEIBMUoFCgEzEGRKBQoBMRAAUg4SBDI5LiogAigAKAEoAhJwCi5QcmVyZW5kZXJMb2NhbFByZWRpY3Rvck1heENvbmN1cnJlbnRQcmVyZW5kZXJzGMS0jZYFOAFCATFKBQoBMRAUSgUKATIQFEoFCgEzEBRKBQoBNBAUSgUKATUQFFIQEgQyOS4qIAAgASgAKAEoAhJjCiVQcmVyZW5kZXJMb2NhbFByZWRpY3RvclByZXJlbmRlckxhbmNoGMS0jZYFOABCB0VuYWJsZWRKDAoIRGlzYWJsZWQQAEoLCgdFbmFibGVkEGRSDhIEMjkuKiACKAAoASgCEmMKJVByZXJlbmRlckxvY2FsUHJlZGljdG9yUHJlcmVuZGVyTGFuY2gYxLSNlgU4AUIHRW5hYmxlZEoMCghEaXNhYmxlZBBkSgsKB0VuYWJsZWQQAFIOEgQyOS4qIAMoACgBKAISZwo7UHJlcmVuZGVyTG9jYWxQcmVkaWN0b3JQcmVyZW5kZXJQcmlvcml0eUhhbGZMaWZlVGltZVNlY29uZHMYxLSNlgU4AEIBMEoGCgIzMBBkSgUKATAQAFIOEgQyOS4qIAIoACgBKAIScQo7UHJlcmVuZGVyTG9jYWxQcmVkaWN0b3JQcmVyZW5kZXJQcmlvcml0eUhhbGZMaWZlVGltZVNlY29uZHMYxLSNlgU4AUIBMEoFCgEwEDJKBgoCMzAQGUoGCgI2MBAZUhASBDI5LiogACABKAAoASgCEm4KKlByZXJlbmRlckxvY2FsUHJlZGljdG9yUHJlcmVuZGVyVFRMU2Vjb25kcxjEtI2WBTgBQgMxODBKBwoDMTgwEDRKBwoDMTIwEBBKBwoDMjQwEBBKBgoCNjAQEFIQEgQyOS4qIAAgASgAKAEoAhLRCgobUHJlcmVuZGVyTG9jYWxQcmVkaWN0b3JTcGVjGMSbkqUFOAFCF0xvY2FsUHJlZGljdG9yPURpc2FibGVkSoIBCn1pZD0xOkxvY2FsUHJlZGljdG9yPUVuYWJsZWQ6U2lkZUVmZmVjdEZyZWVXaGl0ZWxpc3Q9RW5hYmxlZDpNYXhDb25jdXJyZW50UHJlcmVuZGVycz0zOlByZXJlbmRlclByaW9yaXR5SGFsZkxpZmVUaW1lU2Vjb25kcz0zMBDFAkqBAQp9aWQ9MjpMb2NhbFByZWRpY3Rvcj1FbmFibGVkOlNpZGVFZmZlY3RGcmVlV2hpdGVsaXN0PUVuYWJsZWQ6TWF4Q29uY3VycmVudFByZXJlbmRlcnM9MzpQcmVyZW5kZXJQcmlvcml0eUhhbGZMaWZlVGltZVNlY29uZHM9MzAQS0p8CnhMb2NhbFByZWRpY3Rvcj1FbmFibGVkOlNpZGVFZmZlY3RGcmVlV2hpdGVsaXN0PUVuYWJsZWQ6TWF4Q29uY3VycmVudFByZXJlbmRlcnM9MjpQcmVyZW5kZXJQcmlvcml0eUhhbGZMaWZlVGltZVNlY29uZHM9MzAQS0p8CnhMb2NhbFByZWRpY3Rvcj1FbmFibGVkOlNpZGVFZmZlY3RGcmVlV2hpdGVsaXN0PUVuYWJsZWQ6TWF4Q29uY3VycmVudFByZXJlbmRlcnM9MTpQcmVyZW5kZXJQcmlvcml0eUhhbGZMaWZlVGltZVNlY29uZHM9MzAQS0p7CndMb2NhbFByZWRpY3Rvcj1FbmFibGVkOlNpZGVFZmZlY3RGcmVlV2hpdGVsaXN0PUVuYWJsZWQ6TWF4Q29uY3VycmVudFByZXJlbmRlcnM9MzpQcmVyZW5kZXJQcmlvcml0eUhhbGZMaWZlVGltZVNlY29uZHM9MBBLSnwKeExvY2FsUHJlZGljdG9yPUVuYWJsZWQ6U2lkZUVmZmVjdEZyZWVXaGl0ZWxpc3Q9RW5hYmxlZDpNYXhDb25jdXJyZW50UHJlcmVuZGVycz0zOlByZXJlbmRlclByaW9yaXR5SGFsZkxpZmVUaW1lU2Vjb25kcz02MBBLSpYBCpEBTG9jYWxQcmVkaWN0b3I9RW5hYmxlZDpTaWRlRWZmZWN0RnJlZVdoaXRlbGlzdD1FbmFibGVkOk1heENvbmN1cnJlbnRQcmVyZW5kZXJzPTM6UHJlcmVuZGVyUHJpb3JpdHlIYWxmTGlmZVRpbWVTZWNvbmRzPTMwOlByZXJlbmRlckxhdW5jaD1EaXNhYmxlZBBLSpwBCpcBTG9jYWxQcmVkaWN0b3I9RW5hYmxlZDpTaWRlRWZmZWN0RnJlZVdoaXRlbGlzdD1FbmFibGVkOk1heENvbmN1cnJlbnRQcmVyZW5kZXJzPTM6UHJlcmVuZGVyUHJpb3JpdHlIYWxmTGlmZVRpbWVTZWNvbmRzPTMwOlByZXJlbmRlckFsd2F5c0NvbnRyb2w9RW5hYmxlZBBLSqsBCqYBTG9jYWxQcmVkaWN0b3I9RW5hYmxlZDpTaWRlRWZmZWN0RnJlZVdoaXRlbGlzdD1FbmFibGVkOk1heENvbmN1cnJlbnRQcmVyZW5kZXJzPTM6UHJlcmVuZGVyUHJpb3JpdHlIYWxmTGlmZVRpbWVTZWNvbmRzPTMwOlByZXJlbmRlckxhdW5jaD1EaXNhYmxlZDpTa2lwTG9nZ2VkSW49RW5hYmxlZBBLShsKF0xvY2FsUHJlZGljdG9yPURpc2FibGVkEEtSDhIEMzAuKiACKAAoASgCEvgGChtQcmVyZW5kZXJMb2NhbFByZWRpY3RvclNwZWMYxJuSpQU4AUIcY2Q9MzpMb2NhbFByZWRpY3Rvcj1EaXNhYmxlZEqCAQp+Y2Q9MWE6TG9jYWxQcmVkaWN0b3I9RW5hYmxlZDpTaWRlRWZmZWN0RnJlZVdoaXRlbGlzdD1FbmFibGVkOk1heENvbmN1cnJlbnRQcmVyZW5kZXJzPTM6UHJlcmVuZGVyUHJpb3JpdHlIYWxmTGlmZVRpbWVTZWNvbmRzPTMwEDJKsgEKrQFjZD0xZTpMb2NhbFByZWRpY3Rvcj1FbmFibGVkOlNpZGVFZmZlY3RGcmVlV2hpdGVsaXN0PUVuYWJsZWQ6TWF4Q29uY3VycmVudFByZXJlbmRlcnM9MzpQcmVyZW5kZXJQcmlvcml0eUhhbGZMaWZlVGltZVNlY29uZHM9MzA6RGlzYWJsZVNlc3Npb25TdG9yYWdlTmFtZXNwYWNlTWVyZ2luZz1EaXNhYmxlZBAySs4BCskBY2Q9MmE6TG9jYWxQcmVkaWN0b3I9RW5hYmxlZDpTaWRlRWZmZWN0RnJlZVdoaXRlbGlzdD1FbmFibGVkOk1heENvbmN1cnJlbnRQcmVyZW5kZXJzPTM6UHJlcmVuZGVyUHJpb3JpdHlIYWxmTGlmZVRpbWVTZWNvbmRzPTMwOlByZXJlbmRlclF1ZXJ5UHJlcmVuZGVyU2VydmljZT1FbmFibGVkOlByZXJlbmRlclNlcnZpY2VGZXRjaFRpbWVvdXRNcz01MDAwEDJK8wEK7gFjZD0yYjpMb2NhbFByZWRpY3Rvcj1FbmFibGVkOlNpZGVFZmZlY3RGcmVlV2hpdGVsaXN0PUVuYWJsZWQ6TWF4Q29uY3VycmVudFByZXJlbmRlcnM9MzpQcmVyZW5kZXJQcmlvcml0eUhhbGZMaWZlVGltZVNlY29uZHM9MzA6UHJlcmVuZGVyUXVlcnlQcmVyZW5kZXJTZXJ2aWNlPUVuYWJsZWQ6UHJlcmVuZGVyU2VydmljZUZldGNoVGltZW91dE1zPTUwMDA6U2tpcFByZXJlbmRlckxvY2FsQ2FuZGlkYXRlcz1FbmFibGVkEDJKIAocY2Q9MzpMb2NhbFByZWRpY3Rvcj1EaXNhYmxlZBBkUhASBDMxLiogACABKAAoASgCEosEChtQcmVyZW5kZXJMb2NhbFByZWRpY3RvclNwZWMYxJuSpQU4AUIXTG9jYWxQcmVkaWN0b3I9RGlzYWJsZWRKqgEKpQFMYWJlbD1TdGFibGUyOkxvY2FsUHJlZGljdG9yPUVuYWJsZWQ6U2lkZUVmZmVjdEZyZWVXaGl0ZWxpc3Q9RW5hYmxlZDpNYXhDb25jdXJyZW50UHJlcmVuZGVycz0zOlByZXJlbmRlclByaW9yaXR5SGFsZkxpZmVUaW1lU2Vjb25kcz0zMDpQcmVyZW5kZXJBbHdheXNDb250cm9sPUVuYWJsZWQQMkq8AQq3AUxhYmVsPVN0YWJsZTM6TG9jYWxQcmVkaWN0b3I9RW5hYmxlZDpTaWRlRWZmZWN0RnJlZVdoaXRlbGlzdD1FbmFibGVkOk1heENvbmN1cnJlbnRQcmVyZW5kZXJzPTM6UHJlcmVuZGVyUHJpb3JpdHlIYWxmTGlmZVRpbWVTZWNvbmRzPTMwOlByZXJlbmRlckFsd2F5c0NvbnRyb2w9RW5hYmxlZDpTa2lwSFRUUFM9RW5hYmxlZBAySjEKLUxhYmVsPVN0YWJsZUNvbnRyb2w1MDpMb2NhbFByZWRpY3Rvcj1EaXNhYmxlZBAyShwKF0xvY2FsUHJlZGljdG9yPURpc2FibGVkEPpMUg4SBDMwLiogAygAKAEoAhJWChdQcmVyZW5kZXJMb2NhbFByZWRpY3RvchjEtI2WBTgBQghEaXNhYmxlZEoLCgdFbmFibGVkEAFKDAoIRGlzYWJsZWQQY1IOEgQyOS4qIAMoACgBKAISVgoSTWFudWFsUmVzZXRQcm9maWxlGMSz05UFOAFCB0Rpc2FibGVKCgoGRW5hYmxlEGRKCwoHRGlzYWJsZRAAUhYSBDI5LiogACABIAIgAygAKAEoAygCEvkBCg9Qcm9ncmVzc2l2ZVNjYW4YxLSNlgU4AUIHRGVmYXVsdEoVChEzM1BlcmNlbnRfNE1pbk1heBAyShUKETUwUGVyY2VudF80TWluTWF4EABKFQoRNTBQZXJjZW50XzhNaW5NYXgQAEoWChIxMDBQZXJjZW50XzhNaW5NYXgQAEoMCghGdWxsU2NhbhAyShkKFTEwMFBlcmNlbnRfMU1pblNlZW5fQRAyShkKFTEwMFBlcmNlbnRfMU1pblNlZW5fQhAyShgKFDEwMFBlcmNlbnRfMU1pbl80TWF4EDJKDAoHRGVmYXVsdBDuBVIMEgQzMi4qIAAgASgDEqICCgRRVUlDGMT4jKUFOABCCERpc2FibGVkShUKDEh0dHBzRW5hYmxlZBAEGIeSygFKFQoMQ29udHJvbEh0dHBzEAQYiJLKAUoeCgxGbGFnRGlzYWJsZWQQACoMZGlzYWJsZS1xdWljSicKEEZsYWdIdHRwc0VuYWJsZWQQACoRZW5hYmxlLXF1aWMtaHR0cHNKKQoRRmxhZ0h0dHBzRGlzYWJsZWQQACoSZGlzYWJsZS1xdWljLWh0dHBzShwKC0ZsYWdFbmFibGVkEAAqC2VuYWJsZS1xdWljSigKDkZsYWdQYWNrZXRTaXplEAAqFHF1aWMtbWF4LXBhY2tldC1zaXplSgwKCERpc2FibGVkEFxSEBIMMzQuMC4xODQ3LjYwIAIShwMKBFFVSUMYxPiMpQU4AEIIRGlzYWJsZWRKEAoHRW5hYmxlZBAIGP+RygFKHwoWRW5hYmxlZDEzNTBCeXRlUGFja2V0cxAVGIOSygFKFQoMSHR0cHNFbmFibGVkEBUY/5HKAUoQCgdDb250cm9sEAgYgJLKAUofChZDb250cm9sMTM1MEJ5dGVQYWNrZXRzEBUYhJLKAUoVCgxDb250cm9sSHR0cHMQFRiAksoBSh4KDEZsYWdEaXNhYmxlZBAAKgxkaXNhYmxlLXF1aWNKJwoQRmxhZ0h0dHBzRW5hYmxlZBAAKhFlbmFibGUtcXVpYy1odHRwc0opChFGbGFnSHR0cHNEaXNhYmxlZBAAKhJkaXNhYmxlLXF1aWMtaHR0cHNKHAoLRmxhZ0VuYWJsZWQQACoLZW5hYmxlLXF1aWNKKAoORmxhZ1BhY2tldFNpemUQACoUcXVpYy1tYXgtcGFja2V0LXNpemVKDAoIRGlzYWJsZWQQAFIPEgszNS4wLjE4ODEuMCAAEocDCgRRVUlDGMT4jKUFOABCCERpc2FibGVkShAKB0VuYWJsZWQQABiBksoBSh8KFkVuYWJsZWQxMzUwQnl0ZVBhY2tldHMQBBiDksoBShUKDEh0dHBzRW5hYmxlZBAEGIWSygFKEAoHQ29udHJvbBAAGIKSygFKHwoWQ29udHJvbDEzNTBCeXRlUGFja2V0cxAEGISSygFKFQoMQ29udHJvbEh0dHBzEAQYhpLKAUoeCgxGbGFnRGlzYWJsZWQQACoMZGlzYWJsZS1xdWljSicKEEZsYWdIdHRwc0VuYWJsZWQQACoRZW5hYmxlLXF1aWMtaHR0cHNKKQoRRmxhZ0h0dHBzRGlzYWJsZWQQACoSZGlzYWJsZS1xdWljLWh0dHBzShwKC0ZsYWdFbmFibGVkEAAqC2VuYWJsZS1xdWljSigKDkZsYWdQYWNrZXRTaXplEAAqFHF1aWMtbWF4LXBhY2tldC1zaXplSgwKCERpc2FibGVkEFRSDxILMzUuMC4xODgzLjAgARKiAgoEUVVJQxjE+IylBTgAQghEaXNhYmxlZEoVCgxIdHRwc0VuYWJsZWQQABiJksoBShUKDENvbnRyb2xIdHRwcxAAGIqSygFKHgoMRmxhZ0Rpc2FibGVkEAAqDGRpc2FibGUtcXVpY0onChBGbGFnSHR0cHNFbmFibGVkEAAqEWVuYWJsZS1xdWljLWh0dHBzSikKEUZsYWdIdHRwc0Rpc2FibGVkEAAqEmRpc2FibGUtcXVpYy1odHRwc0ocCgtGbGFnRW5hYmxlZBAAKgtlbmFibGUtcXVpY0ooCg5GbGFnUGFja2V0U2l6ZRAAKhRxdWljLW1heC1wYWNrZXQtc2l6ZUoMCghEaXNhYmxlZBBkUhASDDM0LjAuMTg0Ny42MCADEjYKDlNCSW50ZXJzdGl0aWFsGMDSjYkFOAFCAlYxSgYKAlYxEAFKBgoCVjIQY1IIKAAoASgCKAMSWgoPU1JQU2VhcmNoQnV0dG9uGMSqsqEFOAFCCE5vQnV0dG9uSgoKBkJ1dHRvbhAKSgsKB0NvbnRyb2wQCkoMCghOb0J1dHRvbhBQUg4SBDMyLiogACABKAAoARKwAQoYU2VuZEZlZWRiYWNrTGlua0xvY2F0aW9uGMCSgpEFOAFCB2RlZmF1bHRKEAoHZGVmYXVsdBAoGKmFygFKEAoHY29udHJvbBAPGPiEygFKEQoIYWx0LXRleHQQDxj8hMoBShUKDGFsdC1sb2NhdGlvbhAPGIKFygFKHgoVYWx0LXRleHQtYW5kLWxvY2F0aW9uEA8YiIXKAVIVEgsyNy4wLjE0NTMuKiACKAAoAigBEqwBChhTZW5kRmVlZGJhY2tMaW5rTG9jYXRpb24YwJKCkQU4AUIHZGVmYXVsdEoQCgdkZWZhdWx0ECgYqYXKAUoQCgdjb250cm9sEA8Y+YTKAUoRCghhbHQtdGV4dBAPGP+EygFKFQoMYWx0LWxvY2F0aW9uEA8YhYXKAUoeChVhbHQtdGV4dC1hbmQtbG9jYXRpb24QDxiLhcoBUhESCzI3LjAuMTQ1My4qIAIoAxKyAQoYU2VuZEZlZWRiYWNrTGlua0xvY2F0aW9uGMCSgpEFOAFCB2RlZmF1bHRKEAoHZGVmYXVsdBAoGKmFygFKEAoHY29udHJvbBAPGPiEygFKEQoIYWx0LXRleHQQDxj6hMoBShUKDGFsdC1sb2NhdGlvbhAPGICFygFKHgoVYWx0LXRleHQtYW5kLWxvY2F0aW9uEA8YhoXKAVIXEgsyNy4wLjE0NTMuKiABIAAoACgCKAESrgEKGFNlbmRGZWVkYmFja0xpbmtMb2NhdGlvbhjAkoKRBTgBQgdkZWZhdWx0ShAKB2RlZmF1bHQQKBiphcoBShAKB2NvbnRyb2wQDxj5hMoBShEKCGFsdC10ZXh0EA8Y/YTKAUoVCgxhbHQtbG9jYXRpb24QDxiDhcoBSh4KFWFsdC10ZXh0LWFuZC1sb2NhdGlvbhAPGImFygFSExILMjcuMC4xNDUzLiogASAAKAMSsAEKGFNlbmRGZWVkYmFja0xpbmtMb2NhdGlvbhjAkoKRBTgBQgdkZWZhdWx0ShAKB2RlZmF1bHQQPBiphcoBShAKB2NvbnRyb2wQChj4hMoBShEKCGFsdC10ZXh0EAoY+4TKAUoVCgxhbHQtbG9jYXRpb24QChiBhcoBSh4KFWFsdC10ZXh0LWFuZC1sb2NhdGlvbhAKGIeFygFSFRILMjcuMC4xNDUzLiogAygAKAIoARKsAQoYU2VuZEZlZWRiYWNrTGlua0xvY2F0aW9uGMCSgpEFOAFCB2RlZmF1bHRKEAoHZGVmYXVsdBA8GKmFygFKEAoHY29udHJvbBAKGPmEygFKEQoIYWx0LXRleHQQChj+hMoBShUKDGFsdC1sb2NhdGlvbhAKGISFygFKHgoVYWx0LXRleHQtYW5kLWxvY2F0aW9uEAoYioXKAVIREgsyNy4wLjE0NTMuKiADKAMSfgoTU2V0dGluZ3NFbmZvcmNlbWVudBjEh62hBTgBQg5lbmZvcmNlX2Fsd2F5c0oSCg5ub19lbmZvcmNlbWVudBBkShMKD2VuZm9yY2Vfb25fbG9hZBAAShIKDmVuZm9yY2VfYWx3YXlzEABSEiAAIAEgAiADKAEoAygCKAUoBBJwChNTZXR0aW5nc0VuZm9yY2VtZW50GMSHraEFOAFCDmVuZm9yY2VfYWx3YXlzShIKDm5vX2VuZm9yY2VtZW50EGRKEwoPZW5mb3JjZV9vbl9sb2FkEABKEgoOZW5mb3JjZV9hbHdheXMQAFIEIAIoABJ/ChNTZXR0aW5nc0VuZm9yY2VtZW50GMSHraEFOAFCDmVuZm9yY2VfYWx3YXlzShIKDm5vX2VuZm9yY2VtZW50EGRKEwoPZW5mb3JjZV9vbl9sb2FkEABKEgoOZW5mb3JjZV9hbHdheXMQAFITEgszNC4wLjE4MzguMiAAIAEoABJwChNTZXR0aW5nc0VuZm9yY2VtZW50GMSHraEFOAFCDmVuZm9yY2VfYWx3YXlzShIKDm5vX2VuZm9yY2VtZW50EGRKEwoPZW5mb3JjZV9vbl9sb2FkEABKEgoOZW5mb3JjZV9hbHdheXMQAFIEIAMoABJ5ChRTaG93QXBwTGF1bmNoZXJQcm9tbzgBQgdEZWZhdWx0SiAKF1Nob3dQcm9tb1VudGlsRGlzbWlzc2VkEGQYnobKAUobChJSZXNldFNob3dQcm9tb1ByZWYQABifhsoBSgsKB0RlZmF1bHQQAFIKIAAgASACIAMoABJiChNTaG93UHJvZmlsZVN3aXRjaGVyGMDK4IoFOAFCB2RlZmF1bHRKCwoHZGVmYXVsdBBQSgsKB2NvbnRyb2wQCkoOCgpBbHdheXNTaG93EApSEBIEMjYuKiAAIAEoACgBKAISVwoPU2lkZWxvYWRXaXBlb3V0GMScnYsFOAFCCERpc2FibGVkSgwKCERpc2FibGVkEABKCwoHRW5hYmxlZBBkUhcSCzI1LjAuMTM2MC4qIAAgASACIAMoABJ3ChpTaWduSW5Ub0Nocm9tZUNvbmZpcm1hdGlvbhjAyuCKBTgBQgdkZWZhdWx0SgsKB2RlZmF1bHQQUEoUChBjb250cm9sX0RJU0FCTEVEEApKEwoPQnViYmxlX0RJU0FCTEVEEApSEBIEMjYuKiAAIAEoACgBKAIShAEKEFNpbXBsZUNhY2hlVHJpYWwYxLSNlgU4AUIMRXhwZXJpbWVudE5vShIKDkV4cGVyaW1lbnRZZXMyEAVKEQoNRXhwZXJpbWVudFllcxBVShUKEUV4cGVyaW1lbnRDb250cm9sEAVKEAoMRXhwZXJpbWVudE5vEAVSChIEMjkuKiACKAQShgEKEFNpbXBsZUNhY2hlVHJpYWwYxLSNlgU4AUIMRXhwZXJpbWVudE5vShAKDEV4cGVyaW1lbnRObxAAShEKDUV4cGVyaW1lbnRZZXMQUEoSCg5FeHBlcmltZW50WWVzMhAKShUKEUV4cGVyaW1lbnRDb250cm9sEApSDBIEMjguKiAAIAEoBBKLAQowU2ltcGxlQ2FjaGVJbmRleEZsdXNoRGVsYXlfRm9yZWdyb3VuZF9CYWNrZ3JvdW5kGMS0jZYFOAFCCTIwMDAwXzEwMEoMCgg1MDAwXzEwMBAZSgwKCDEwMDBfMTAwEBlKCwoHMTAwMF8yMBAZSg0KCTIwMDAwXzEwMBAZUgwSBDI5LiogACABKAQSYQoVU2ltcGxlQ2FjaGVNYXhUaHJlYWRzGMS0jZYFOABCAjUwSgUKATEQCkoFCgE1EBJKBgoCMTAQEkoGCgIyMBASSgYKAjMwEBJKBgoCNTAQElIOEgQyOS4qIAAgASACKAQShAEKEFNpbXBsZUNhY2hlVHJpYWwYxJuSpQU4AUIMRXhwZXJpbWVudE5vShIKDkV4cGVyaW1lbnRZZXMyEAFKFQoRRXhwZXJpbWVudENvbnRyb2wQAUoRCg1FeHBlcmltZW50WWVzEFlKEAoMRXhwZXJpbWVudE5vEAlSChIEMzAuKiADKAQSoAMKBFNQRFkYxPiMpQU4AEILU3BkeUVuYWJsZWRKCwoHQ29udHJvbBAFShAKDFNwZHlEaXNhYmxlZBAFSj4KHlNwZHlFbmFibGVkQnlXZWJTb2NrZXRPdmVyU3BkeRAAKhplbmFibGUtd2Vic29ja2V0LW92ZXItc3BkeUo0ChlTcGR5RW5hYmxlZEJ5SHR0cDJEcmFmdDA0EAAqFWVuYWJsZS1odHRwMi1kcmFmdC0wNEooChRTcGR5RW5hYmxlZEJ5U3BkeTRhMhAAKg5lbmFibGUtc3BkeTRhMkomChJTcGR5RW5hYmxlZEJ5U3BkeTMQACoOZGlzYWJsZS1zcGR5MzFKJAoUU3BkeUVuYWJsZWRCeU5wblNwZHkQACoKZW5hYmxlLW5wbkojChVTcGR5RGlzYWJsZWRCeVVzZVNwZHkQACoIdXNlLXNwZHlKKwoWU3BkeURpc2FibGVkQnlIdHRwT25seRAAKg9lbmFibGUtbnBuLWh0dHBKDwoLU3BkeUVuYWJsZWQQWlITEgszMi4wLjE2NTMuMCACKAQoBRKeAwoEU1BEWRjE+IylBTgAQgtTcGR5RW5hYmxlZEoLCgdDb250cm9sEAVKEAoMU3BkeURpc2FibGVkEAVKPgoeU3BkeUVuYWJsZWRCeVdlYlNvY2tldE92ZXJTcGR5EAAqGmVuYWJsZS13ZWJzb2NrZXQtb3Zlci1zcGR5SjQKGVNwZHlFbmFibGVkQnlIdHRwMkRyYWZ0MDQQACoVZW5hYmxlLWh0dHAyLWRyYWZ0LTA0SigKFFNwZHlFbmFibGVkQnlTcGR5NGEyEAAqDmVuYWJsZS1zcGR5NGEySiYKElNwZHlFbmFibGVkQnlTcGR5MxAAKg5kaXNhYmxlLXNwZHkzMUokChRTcGR5RW5hYmxlZEJ5TnBuU3BkeRAAKgplbmFibGUtbnBuSiMKFVNwZHlEaXNhYmxlZEJ5VXNlU3BkeRAAKgh1c2Utc3BkeUorChZTcGR5RGlzYWJsZWRCeUh0dHBPbmx5EAAqD2VuYWJsZS1ucG4taHR0cEoPCgtTcGR5RW5hYmxlZBBaUhESCzMyLjAuMTY1My4wIAAgARKVAwoeU3BlY3VsYXRpdmVSZXNvdXJjZVByZWZldGNoaW5nGICc44oFOAFCCERpc2FibGVkSgwKCERpc2FibGVkEChKEAoMTGVhcm5pbmdIb3N0EApKDwoLTGVhcm5pbmdVUkwQCkoMCghMZWFybmluZxAKShMKD1ByZWZldGNoaW5nSG9zdBAKShIKDlByZWZldGNoaW5nVVJMEApKDwoLUHJlZmV0Y2hpbmcQCkocChhQcmVmZXRjaGluZ0xvd0NvbmZpZGVuY2UQAEodChlQcmVmZXRjaGluZ0hpZ2hDb25maWRlbmNlEABKHAoYUHJlZmV0Y2hpbmdNb3JlUmVzb3VyY2VzEABKEwoPTGVhcm5pbmdTbWFsbERCEABKFgoSUHJlZmV0Y2hpbmdTbWFsbERCEABKIwofUHJlZmV0Y2hpbmdTbWFsbERCTG93Q29uZmlkZW5jZRAASiQKIFByZWZldGNoaW5nU21hbGxEQkhpZ2hDb25maWRlbmNlEABSFRILMjUuMC4xMzY0LiogAigAKAEoAhKXAwoeU3BlY3VsYXRpdmVSZXNvdXJjZVByZWZldGNoaW5nGICc44oFOAFCCERpc2FibGVkSgwKCERpc2FibGVkEChKEAoMTGVhcm5pbmdIb3N0EApKDwoLTGVhcm5pbmdVUkwQCkoMCghMZWFybmluZxAKShMKD1ByZWZldGNoaW5nSG9zdBAKShIKDlByZWZldGNoaW5nVVJMEApKDwoLUHJlZmV0Y2hpbmcQCkocChhQcmVmZXRjaGluZ0xvd0NvbmZpZGVuY2UQAEodChlQcmVmZXRjaGluZ0hpZ2hDb25maWRlbmNlEABKHAoYUHJlZmV0Y2hpbmdNb3JlUmVzb3VyY2VzEABKEwoPTGVhcm5pbmdTbWFsbERCEABKFgoSUHJlZmV0Y2hpbmdTbWFsbERCEABKIwofUHJlZmV0Y2hpbmdTbWFsbERCTG93Q29uZmlkZW5jZRAASiQKIFByZWZldGNoaW5nU21hbGxEQkhpZ2hDb25maWRlbmNlEABSFxILMjUuMC4xMzY0LiogACABKAAoASgCEl0KFVNwZWN1bGF0aXZlVGFiUmVzdG9yZRjEguiZBTgBQghEaXNhYmxlZEoLCgdFbmFibGVkEApKCwoHQ29udHJvbBAKSgwKCERpc2FibGVkEFBSChIEMzEuKiACKAQSXwoVU3BlY3VsYXRpdmVUYWJSZXN0b3JlGMSC6JkFOAFCCERpc2FibGVkSgsKB0VuYWJsZWQQMkoLCgdDb250cm9sEDJKDAoIRGlzYWJsZWQQAFIMEgQzMS4qIAAgASgEElIKClNwZWxsY2hlY2sYxNu0jQU4AUIHRGVmYXVsdEoLCgdEZWZhdWx0EGRKDwoLU3VnZ2VzdGlvbnMQAFIVEgsyNi4wLjE0MDMuMCACIAEgACgAElQKClNwZWxsY2hlY2sYxNu0jQU4AUIHRGVmYXVsdEoLCgdEZWZhdWx0EGRKDwoLU3VnZ2VzdGlvbnMQAFIXEgsyNi4wLjE0MDMuMCADIAIgASgCKAMSTgoKU3BlbGxjaGVjaxjE27SNBTgBQgdEZWZhdWx0SgsKB0RlZmF1bHQQZEoPCgtTdWdnZXN0aW9ucxAAUhESCzI2LjAuMTQwMy4wIAMoABJPCg1FbmFibGVTdGFnZTNEGICI/oYFOAFCB2VuYWJsZWRKDAoHZW5hYmxlZBC2B0oPCgtibGFja2xpc3RlZBAyUg4SBDIyLiogACABIAIoABJRCg1FbmFibGVTdGFnZTNEGICI/oYFOAFCB2VuYWJsZWRKDAoHZW5hYmxlZBDoB0oPCgtibGFja2xpc3RlZBAAUhASBDIyLioaBDIyLiogAygAEmgKDUVuYWJsZVN0YWdlM0QYgN+/iQU4AUIPZW5hYmxlZF9kZWZhdWx0ShMKD2VuYWJsZWRfZGVmYXVsdBAASgwKB2VuYWJsZWQQ6AdKDwoLYmxhY2tsaXN0ZWQQAFIKEgQyMy4qIAMoABK0AgoLVGFiRXZpY3Rpb24YgPmMpQU4AUIHRGVmYXVsdEoLCgdDb250cm9sEDJKEQoNTWVtb3J5S2VlcEFsbBAAShMKD01lbW9yeUV2aWN0SGFsZhAAShMKD01lbW9yeUtlZXBUaHJlZRAAShQKEE1lbW9yeUV2aWN0VGhyZWUQAEoYChRCYWNrZ3JvdW5kaW5nS2VlcEFsbBAAShoKFkJhY2tncm91bmRpbmdFdmljdEhhbGYQAEoYChRCYWNrZ3JvdW5kaW5nS2VlcE9uZRAAShsKF0JhY2tncm91bmRpbmdFdmljdFRocmVlEABKEgoOTm9QcmVyZW5kZXJpbmcQMkoPCgtOb1F1aWNrYmFjaxAySgwKB0RlZmF1bHQQ0gZSFBIEMjkuKhoEMzEuKiAAIAIgAygFEtoCCgtUYWJFdmljdGlvbhiAxYqYBTgBQgdEZWZhdWx0SgsKB0NvbnRyb2wQMkoRCg1NZW1vcnlLZWVwQWxsEABKEwoPTWVtb3J5RXZpY3RIYWxmEABKEwoPTWVtb3J5S2VlcFRocmVlEDJKEQoNTWVtb3J5S2VlcFR3bxAyShQKEE1lbW9yeUV2aWN0VGhyZWUQAEoYChRCYWNrZ3JvdW5kaW5nS2VlcEFsbBAAShoKFkJhY2tncm91bmRpbmdFdmljdEhhbGYQAEoYChRCYWNrZ3JvdW5kaW5nS2VlcE9uZRAAShsKF0JhY2tncm91bmRpbmdFdmljdFRocmVlEABKEgoOTm9QcmVyZW5kZXJpbmcQMkoPCgtOb1F1aWNrYmFjaxAyShEKDU1lbW9yeUNvbnRyb2wQMkoMCgdEZWZhdWx0ELwFUhQSBDMyLioaBDMyLiogACACIAMoBRKwAwoLVGFiRXZpY3Rpb24YgPmMpQU4AUIHRGVmYXVsdEoMCgdDb250cm9sEPoBShEKDU1lbW9yeUtlZXBBbGwQAEoTCg9NZW1vcnlFdmljdEhhbGYQAEoTCg9NZW1vcnlLZWVwVGhyZWUQAEoRCg1NZW1vcnlLZWVwVHdvEABKFAoQTWVtb3J5RXZpY3RUaHJlZRAAShgKFEJhY2tncm91bmRpbmdLZWVwQWxsEABKGgoWQmFja2dyb3VuZGluZ0V2aWN0SGFsZhAAShgKFEJhY2tncm91bmRpbmdLZWVwT25lEABKGwoXQmFja2dyb3VuZGluZ0V2aWN0VGhyZWUQAEoSCg5Ob1ByZXJlbmRlcmluZxAASg8KC05vUXVpY2tiYWNrEABKIQocVGFiUHJvdGVjdGlvbkFueUZvcm1BY3Rpdml0eRD6AUoiCh1UYWJQcm90ZWN0aW9uTW9zdEZvcm1BY3Rpdml0eRD6AUokCh9UYWJQcm90ZWN0aW9uTGF0ZXN0Rm9ybUFjdGl2aXR5EPoBSgsKB0RlZmF1bHQQAFIQEgQzMy4qGgQzMy4qIAIoBRLMAwoLVGFiRXZpY3Rpb24YgPmMpQU4AUIHRGVmYXVsdEoLCgdDb250cm9sEABKEQoNTWVtb3J5S2VlcEFsbBAAShMKD01lbW9yeUV2aWN0SGFsZhAAShMKD01lbW9yeUtlZXBUaHJlZRAAShEKDU1lbW9yeUtlZXBUd28QAEoUChBNZW1vcnlFdmljdFRocmVlEABKGAoUQmFja2dyb3VuZGluZ0tlZXBBbGwQAEoaChZCYWNrZ3JvdW5kaW5nRXZpY3RIYWxmEABKGAoUQmFja2dyb3VuZGluZ0tlZXBPbmUQAEobChdCYWNrZ3JvdW5kaW5nRXZpY3RUaHJlZRAAShIKDk5vUHJlcmVuZGVyaW5nEABKDwoLTm9RdWlja2JhY2sQAEodChlUYWJQcm90ZWN0aW9uTm9Qcm90ZWN0aW9uEDJKIAocVGFiUHJvdGVjdGlvbkFueUZvcm1BY3Rpdml0eRAASiEKHVRhYlByb3RlY3Rpb25Nb3N0Rm9ybUFjdGl2aXR5EDJKIwofVGFiUHJvdGVjdGlvbkxhdGVzdEZvcm1BY3Rpdml0eRAySgwKB0RlZmF1bHQQ0gZSEBIEMzMuKhoEMzMuKiADKAUSTgoTVGVzdDBQZXJjZW50RGVmYXVsdBiAnJKlBTgBQgdkZWZhdWx0SgsKB2RlZmF1bHQQAEoMCghncm91cF8wMRBkSgsKB2RvZ2Zvb2QQABJhChhUcmFuc2xhdGVJbmZvYmFyVnNCdWJibGUYxLmvmAU4AUIHRGVmYXVsdEoLCgdJbmZvYmFyEAFKCgoGQnViYmxlEAFKCwoHRGVmYXVsdBBiUg4SBDMyLiogACABKAAoAxKXAgocVU1BLUR5bmFtaWMtVW5pZm9ybWl0eS1UcmlhbBiAnJKlBTgBQgdEZWZhdWx0ShQKBkdyb3VwMRABGL+2yQEgv7bJAUoUCgZHcm91cDIQCRjAtskBIMC2yQFKFQoGR3JvdXAzEOoDGMG2yQEgwbbJAUoUCgZHcm91cDQQARjCtskBIMK2yQFKFAoGR3JvdXA1EAkYw7bJASDDtskBShUKBkdyb3VwNhDqAxjEtskBIMS2yQFKOQoGR3JvdXA3EAAYxrbJASDGtskBKiN1bWEtZHluYW1pYy11bmlmb3JtaXR5LXRyaWFsLWdyb3VwN0oVCgdEZWZhdWx0EAAYxbbJASDFtskBUgwSBDI3LiogAygAKAFgARJaChdVTUEtUG9wdWxhdGlvbi1SZXN0cmljdBiAnJKlBTgBQgdkZWZhdWx0SgsKB2RlZmF1bHQQAEoKCgZub3JtYWwQZEoLCgdkb2dmb29kEABSBhIEMzIuKmABElgKDFVNQVN0YWJpbGl0eRjEyomgBTgBQgtTZXBhcmF0ZUxvZ0oLCgdEZWZhdWx0EABKDwoLU2VwYXJhdGVMb2cQZFIVEgszNC4wLjE4MDEuMCAAIAEgAiADEmEKDFVNQVN0YWJpbGl0eRjEyomgBTgBQgtTZXBhcmF0ZUxvZ0oLCgdEZWZhdWx0EABKDwoLU2VwYXJhdGVMb2cQZFIeEgwzMy4wLjE3NTAuMTEaBDMzLiogACABIAIgAygFEr0BCh9VTUEtVW5pZm9ybWl0eS1UcmlhbC0xMC1QZXJjZW50GICckqUFOAFCB2RlZmF1bHRKCwoHZGVmYXVsdBABSgwKCGdyb3VwXzAxEAFKDAoIZ3JvdXBfMDIQAUoMCghncm91cF8wMxABSgwKCGdyb3VwXzA0EAFKDAoIZ3JvdXBfMDUQAUoMCghncm91cF8wNhABSgwKCGdyb3VwXzA3EAFKDAoIZ3JvdXBfMDgQAUoMCghncm91cF8wORABEqYPCh5VTUEtVW5pZm9ybWl0eS1UcmlhbC0xLVBlcmNlbnQYgJySpQU4AUIHZGVmYXVsdEoQCgdkZWZhdWx0EAEYoLXJAUoRCghncm91cF8wMRABGKG1yQFKEQoIZ3JvdXBfMDIQARiitckBShEKCGdyb3VwXzAzEAEYo7XJAUoRCghncm91cF8wNBABGKS1yQFKEQoIZ3JvdXBfMDUQARiltckBShEKCGdyb3VwXzA2EAEYprXJAUoRCghncm91cF8wNxABGKe1yQFKEQoIZ3JvdXBfMDgQARiotckBShEKCGdyb3VwXzA5EAEYqbXJAUoRCghncm91cF8xMBABGKq1yQFKEQoIZ3JvdXBfMTEQARirtckBShEKCGdyb3VwXzEyEAEYrLXJAUoRCghncm91cF8xMxABGK21yQFKEQoIZ3JvdXBfMTQQARiutckBShEKCGdyb3VwXzE1EAEYr7XJAUoRCghncm91cF8xNhABGLC1yQFKEQoIZ3JvdXBfMTcQARixtckBShEKCGdyb3VwXzE4EAEYsrXJAUoRCghncm91cF8xORABGLO1yQFKEQoIZ3JvdXBfMjAQARi0tckBShEKCGdyb3VwXzIxEAEYtbXJAUoRCghncm91cF8yMhABGLa1yQFKEQoIZ3JvdXBfMjMQARi3tckBShEKCGdyb3VwXzI0EAEYuLXJAUoRCghncm91cF8yNRABGLm1yQFKEQoIZ3JvdXBfMjYQARi6tckBShEKCGdyb3VwXzI3EAEYu7XJAUoRCghncm91cF8yOBABGLy1yQFKEQoIZ3JvdXBfMjkQARi9tckBShEKCGdyb3VwXzMwEAEYvrXJAUoRCghncm91cF8zMRABGL+1yQFKEQoIZ3JvdXBfMzIQARjAtckBShEKCGdyb3VwXzMzEAEYwbXJAUoRCghncm91cF8zNBABGMK1yQFKEQoIZ3JvdXBfMzUQARjDtckBShEKCGdyb3VwXzM2EAEYxLXJAUoRCghncm91cF8zNxABGMW1yQFKEQoIZ3JvdXBfMzgQARjGtckBShEKCGdyb3VwXzM5EAEYx7XJAUoRCghncm91cF80MBABGMi1yQFKEQoIZ3JvdXBfNDEQARjJtckBShEKCGdyb3VwXzQyEAEYyrXJAUoRCghncm91cF80MxABGMu1yQFKEQoIZ3JvdXBfNDQQARjMtckBShEKCGdyb3VwXzQ1EAEYzbXJAUoRCghncm91cF80NhABGM61yQFKEQoIZ3JvdXBfNDcQARjPtckBShEKCGdyb3VwXzQ4EAEY0LXJAUoRCghncm91cF80ORABGNG1yQFKEQoIZ3JvdXBfNTAQARjStckBShEKCGdyb3VwXzUxEAEY07XJAUoRCghncm91cF81MhABGNS1yQFKEQoIZ3JvdXBfNTMQARjVtckBShEKCGdyb3VwXzU0EAEY1rXJAUoRCghncm91cF81NRABGNe1yQFKEQoIZ3JvdXBfNTYQARjYtckBShEKCGdyb3VwXzU3EAEY2bXJAUoRCghncm91cF81OBABGNq1yQFKEQoIZ3JvdXBfNTkQARjbtckBShEKCGdyb3VwXzYwEAEY3LXJAUoRCghncm91cF82MRABGN21yQFKEQoIZ3JvdXBfNjIQARjetckBShEKCGdyb3VwXzYzEAEY37XJAUoRCghncm91cF82NBABGOC1yQFKEQoIZ3JvdXBfNjUQARjhtckBShEKCGdyb3VwXzY2EAEY4rXJAUoRCghncm91cF82NxABGOO1yQFKEQoIZ3JvdXBfNjgQARjktckBShEKCGdyb3VwXzY5EAEY5bXJAUoRCghncm91cF83MBABGOa1yQFKEQoIZ3JvdXBfNzEQARjntckBShEKCGdyb3VwXzcyEAEY6LXJAUoRCghncm91cF83MxABGOm1yQFKEQoIZ3JvdXBfNzQQARjqtckBShEKCGdyb3VwXzc1EAEY67XJAUoRCghncm91cF83NhABGOy1yQFKEQoIZ3JvdXBfNzcQARjttckBShEKCGdyb3VwXzc4EAEY7rXJAUoRCghncm91cF83ORABGO+1yQFKEQoIZ3JvdXBfODAQARjwtckBShEKCGdyb3VwXzgxEAEY8bXJAUoRCghncm91cF84MhABGPK1yQFKEQoIZ3JvdXBfODMQARjztckBShEKCGdyb3VwXzg0EAEY9LXJAUoRCghncm91cF84NRABGPW1yQFKEQoIZ3JvdXBfODYQARj2tckBShEKCGdyb3VwXzg3EAEY97XJAUoRCghncm91cF84OBABGPi1yQFKEQoIZ3JvdXBfODkQARj5tckBShEKCGdyb3VwXzkwEAEY+rXJAUoRCghncm91cF85MRABGPu1yQFKEQoIZ3JvdXBfOTIQARj8tckBShEKCGdyb3VwXzkzEAEY/bXJAUoRCghncm91cF85NBABGP61yQFKEQoIZ3JvdXBfOTUQARj/tckBShEKCGdyb3VwXzk2EAEYgLbJAUoRCghncm91cF85NxABGIG2yQFKEQoIZ3JvdXBfOTgQARiCtskBShEKCGdyb3VwXzk5EAEYg7bJAVIIKAAoASgCKAMSrgsKHlVNQS1Vbmlmb3JtaXR5LVRyaWFsLTEtUGVyY2VudBiAnJKlBTgBQgdkZWZhdWx0SgsKB2RlZmF1bHQQAUoMCghncm91cF8wMRABSgwKCGdyb3VwXzAyEAFKDAoIZ3JvdXBfMDMQAUoMCghncm91cF8wNBABSgwKCGdyb3VwXzA1EAFKDAoIZ3JvdXBfMDYQAUoMCghncm91cF8wNxABSgwKCGdyb3VwXzA4EAFKDAoIZ3JvdXBfMDkQAUoMCghncm91cF8xMBABSgwKCGdyb3VwXzExEAFKDAoIZ3JvdXBfMTIQAUoMCghncm91cF8xMxABSgwKCGdyb3VwXzE0EAFKDAoIZ3JvdXBfMTUQAUoMCghncm91cF8xNhABSgwKCGdyb3VwXzE3EAFKDAoIZ3JvdXBfMTgQAUoMCghncm91cF8xORABSgwKCGdyb3VwXzIwEAFKDAoIZ3JvdXBfMjEQAUoMCghncm91cF8yMhABSgwKCGdyb3VwXzIzEAFKDAoIZ3JvdXBfMjQQAUoMCghncm91cF8yNRABSgwKCGdyb3VwXzI2EAFKDAoIZ3JvdXBfMjcQAUoMCghncm91cF8yOBABSgwKCGdyb3VwXzI5EAFKDAoIZ3JvdXBfMzAQAUoMCghncm91cF8zMRABSgwKCGdyb3VwXzMyEAFKDAoIZ3JvdXBfMzMQAUoMCghncm91cF8zNBABSgwKCGdyb3VwXzM1EAFKDAoIZ3JvdXBfMzYQAUoMCghncm91cF8zNxABSgwKCGdyb3VwXzM4EAFKDAoIZ3JvdXBfMzkQAUoMCghncm91cF80MBABSgwKCGdyb3VwXzQxEAFKDAoIZ3JvdXBfNDIQAUoMCghncm91cF80MxABSgwKCGdyb3VwXzQ0EAFKDAoIZ3JvdXBfNDUQAUoMCghncm91cF80NhABSgwKCGdyb3VwXzQ3EAFKDAoIZ3JvdXBfNDgQAUoMCghncm91cF80ORABSgwKCGdyb3VwXzUwEAFKDAoIZ3JvdXBfNTEQAUoMCghncm91cF81MhABSgwKCGdyb3VwXzUzEAFKDAoIZ3JvdXBfNTQQAUoMCghncm91cF81NRABSgwKCGdyb3VwXzU2EAFKDAoIZ3JvdXBfNTcQAUoMCghncm91cF81OBABSgwKCGdyb3VwXzU5EAFKDAoIZ3JvdXBfNjAQAUoMCghncm91cF82MRABSgwKCGdyb3VwXzYyEAFKDAoIZ3JvdXBfNjMQAUoMCghncm91cF82NBABSgwKCGdyb3VwXzY1EAFKDAoIZ3JvdXBfNjYQAUoMCghncm91cF82NxABSgwKCGdyb3VwXzY4EAFKDAoIZ3JvdXBfNjkQAUoMCghncm91cF83MBABSgwKCGdyb3VwXzcxEAFKDAoIZ3JvdXBfNzIQAUoMCghncm91cF83MxABSgwKCGdyb3VwXzc0EAFKDAoIZ3JvdXBfNzUQAUoMCghncm91cF83NhABSgwKCGdyb3VwXzc3EAFKDAoIZ3JvdXBfNzgQAUoMCghncm91cF83ORABSgwKCGdyb3VwXzgwEAFKDAoIZ3JvdXBfODEQAUoMCghncm91cF84MhABSgwKCGdyb3VwXzgzEAFKDAoIZ3JvdXBfODQQAUoMCghncm91cF84NRABSgwKCGdyb3VwXzg2EAFKDAoIZ3JvdXBfODcQAUoMCghncm91cF84OBABSgwKCGdyb3VwXzg5EAFKDAoIZ3JvdXBfOTAQAUoMCghncm91cF85MRABSgwKCGdyb3VwXzkyEAFKDAoIZ3JvdXBfOTMQAUoMCghncm91cF85NBABSgwKCGdyb3VwXzk1EAFKDAoIZ3JvdXBfOTYQAUoMCghncm91cF85NxABSgwKCGdyb3VwXzk4EAFKDAoIZ3JvdXBfOTkQAVIEKAQoBRKQAQofVU1BLVVuaWZvcm1pdHktVHJpYWwtMjAtUGVyY2VudBiAnJKlBTgBQgdkZWZhdWx0ShAKB2RlZmF1bHQQARiitskBShEKCGdyb3VwXzAxEAEYo7bJAUoRCghncm91cF8wMhABGKS2yQFKEQoIZ3JvdXBfMDMQARiltskBShEKCGdyb3VwXzA0EAEYprbJARJNCh9VTUEtVW5pZm9ybWl0eS1UcmlhbC01MC1QZXJjZW50GICckqUFOAFCB2RlZmF1bHRKCwoHZGVmYXVsdBABSgwKCGdyb3VwXzAxEAEStgMKHlVNQS1Vbmlmb3JtaXR5LVRyaWFsLTUtUGVyY2VudBiAnJKlBTgBQgdkZWZhdWx0ShAKB2RlZmF1bHQQARiEtskBShEKCGdyb3VwXzAxEAEYhbbJAUoRCghncm91cF8wMhABGIa2yQFKEQoIZ3JvdXBfMDMQARiHtskBShEKCGdyb3VwXzA0EAEYiLbJAUoRCghncm91cF8wNRABGIm2yQFKEQoIZ3JvdXBfMDYQARiKtskBShEKCGdyb3VwXzA3EAEYi7bJAUoRCghncm91cF8wOBABGIy2yQFKEQoIZ3JvdXBfMDkQARiNtskBShEKCGdyb3VwXzEwEAEYjrbJAUoRCghncm91cF8xMRABGI+2yQFKEQoIZ3JvdXBfMTIQARiQtskBShEKCGdyb3VwXzEzEAEYkbbJAUoRCghncm91cF8xNBABGJK2yQFKEQoIZ3JvdXBfMTUQARiTtskBShEKCGdyb3VwXzE2EAEYlLbJAUoRCghncm91cF8xNxABGJW2yQFKEQoIZ3JvdXBfMTgQARiWtskBShEKCGdyb3VwXzE5EAEYl7bJAVIIKAAoASgCKAMSzgIKHlVNQS1Vbmlmb3JtaXR5LVRyaWFsLTUtUGVyY2VudBiAnJKlBTgBQgdkZWZhdWx0SgsKB2RlZmF1bHQQAUoMCghncm91cF8wMRABSgwKCGdyb3VwXzAyEAFKDAoIZ3JvdXBfMDMQAUoMCghncm91cF8wNBABSgwKCGdyb3VwXzA1EAFKDAoIZ3JvdXBfMDYQAUoMCghncm91cF8wNxABSgwKCGdyb3VwXzA4EAFKDAoIZ3JvdXBfMDkQAUoMCghncm91cF8xMBABSgwKCGdyb3VwXzExEAFKDAoIZ3JvdXBfMTIQAUoMCghncm91cF8xMxABSgwKCGdyb3VwXzE0EAFKDAoIZ3JvdXBfMTUQAUoMCghncm91cF8xNhABSgwKCGdyb3VwXzE3EAFKDAoIZ3JvdXBfMTgQAUoMCghncm91cF8xORABUgQoBCgFElEKDFZvaWNlVHJpZ2dlchjEvpelBTgBQghEaXNhYmxlZEoLCgdJbnN0YWxsEGRKDAoIRGlzYWJsZWQQAFIUEgQzNC4qIAAgASACKAAoASgCKAMSgAEKFldlYkdMRGVidWdSZW5kZXJlckluZm8YxILomQU4AUIHZW5hYmxlZEoQCgdjb250cm9sEAAYxpLKAUoRCghkaXNhYmxlZBAAGMeSygFKEAoHZW5hYmxlZBBkGMWSygFSHhIEMzEuKhoEMzIuKiADIAIgACABKAAoASgDKAIoBBJzChlXZWJzdG9yZURvd25sb2FkRGlyZWN0b3J5GMT8rpwFOAFCB0RlZmF1bHRKHQoZU2VwYXJhdGVEaXJlY3RvcnlVbmRlclVERBAKSgsKB0NvbnRyb2wQCkoLCgdEZWZhdWx0EFBSDCAAIAEgAigAKAEoAhJvChlXZWJzdG9yZURvd25sb2FkRGlyZWN0b3J5GMT8rpwFOAFCB0RlZmF1bHRKHQoZU2VwYXJhdGVEaXJlY3RvcnlVbmRlclVERBABSgsKB0NvbnRyb2wQAUoLCgdEZWZhdWx0EGJSCCADKAAoASgC", + "variations_seed_signature": "MEUCIQDWcDJZZ+Hi3eyyoOGUf5R5Fp0h5+28JIYT9F3s1upVxQIgdCbBPpn0KHHhZXtRQ31EIbyfyCW6mQAD779yy38VIeM=" +} \ No newline at end of file diff --git a/agent/installer/ns_json/Examples/nsJSON/MultiTree.nsi b/agent/installer/ns_json/Examples/nsJSON/MultiTree.nsi new file mode 100644 index 00000000000..68a82d0c55e --- /dev/null +++ b/agent/installer/ns_json/Examples/nsJSON/MultiTree.nsi @@ -0,0 +1,26 @@ +!include MUI2.nsh + +Name `nsJSON plug-in` +OutFile nsJSON_MultiTree.exe +RequestExecutionLevel user +ShowInstDetails show + +!insertmacro MUI_PAGE_INSTFILES + +!insertmacro MUI_LANGUAGE English + +Section + + CreateDirectory $EXEDIR\Output + + DetailPrint `Read: $EXEDIR\Input\Example1.json into Example1` + nsJSON::Set /tree Example1 /file $EXEDIR\Input\Example1.json + DetailPrint `Read: $EXEDIR\Input\Example2.json into Example2` + nsJSON::Set /tree Example2 /file $EXEDIR\Input\Example2.json + + DetailPrint `Generate: $EXEDIR\Output\Example2.json from Example2` + nsJSON::Serialize /tree Example2 /format /file $EXEDIR\Output\Example2.json + DetailPrint `Generate: $EXEDIR\Output\Example1.json from Example1` + nsJSON::Serialize /tree Example1 /format /file $EXEDIR\Output\Example1.json + +SectionEnd \ No newline at end of file diff --git a/agent/installer/ns_json/Examples/nsJSON/Quote.nsi b/agent/installer/ns_json/Examples/nsJSON/Quote.nsi new file mode 100644 index 00000000000..4ae692d8b7f --- /dev/null +++ b/agent/installer/ns_json/Examples/nsJSON/Quote.nsi @@ -0,0 +1,46 @@ +!include MUI2.nsh + +Name `nsJSON plug-in` +OutFile nsJSON_Quote.exe +RequestExecutionLevel user +ShowInstDetails show + +!insertmacro MUI_PAGE_INSTFILES + +!insertmacro MUI_LANGUAGE English + +!macro nJSON_Quote_Test Unicode Always Input + !if `${Always}` == true + nsJSON::Quote /always `${Input}` + !else if `${Unicode}` == true + nsJSON::Quote /unicode `${Input}` + !else + nsJSON::Quote `${Input}` + !endif + Pop $R0 + !if `${Always}` == true + DetailPrint `${Input} -> $R0 (/always)` + !else if `${Unicode}` == true + DetailPrint `${Input} -> $R0 (/unicode)` + !else + DetailPrint `${Input} -> $R0` + !endif +!macroend +!define nJSON_Quote_Test `!insertmacro nJSON_Quote_Test false false` +!define nJSON_Quote_Test_Unicode `!insertmacro nJSON_Quote_Test true false` +!define nJSON_Quote_Test_Always `!insertmacro nJSON_Quote_Test false true` + +Section + + ${nJSON_Quote_Test} `"` + ${nJSON_Quote_Test} `\` + ${nJSON_Quote_Test} `£` + ${nJSON_Quote_Test} `¡` + ${nJSON_Quote_Test} `"¡"` + ${nJSON_Quote_Test} `"some"text"` + ${nJSON_Quote_Test_Always} `"some"text"` + ${nJSON_Quote_Test_Unicode} `£` + ${nJSON_Quote_Test_Unicode} `¡` + ${nJSON_Quote_Test_Unicode} `"¡"` + +SectionEnd \ No newline at end of file diff --git a/agent/installer/ns_json/Examples/nsJSON/Sort.nsi b/agent/installer/ns_json/Examples/nsJSON/Sort.nsi new file mode 100644 index 00000000000..0f2f0591e41 --- /dev/null +++ b/agent/installer/ns_json/Examples/nsJSON/Sort.nsi @@ -0,0 +1,36 @@ +!include MUI2.nsh + +Name `nsJSON plug-in` +OutFile nsJSON_Sort.exe +RequestExecutionLevel user +ShowInstDetails show + +!insertmacro MUI_PAGE_INSTFILES + +!insertmacro MUI_LANGUAGE English + +!macro nJSON_Sort_Test Options + nsJSON::Sort /options ${Options} /end + nsJSON::Get /end + Pop $R0 + DetailPrint $R0 +!macroend +!define nJSON_Sort_Test `!insertmacro nJSON_Sort_Test` + +Section + + nsJSON::Set /value `{ "D": "X", "b": 3, "a": 22, "c" : 2, "d": "x", "y": { "f": 33, "a": 9, "n": [ 1, 5, -10, 11, "m" ] } }` /end + + DetailPrint `Sorted root node values only` + ${nJSON_Sort_Test} 0 + + DetailPrint `Sorted root node values only numerically` + ${nJSON_Sort_Test} 2 + + DetailPrint `Sorted root node by keys only` + ${nJSON_Sort_Test} 8 + + DetailPrint `Sorted values numerically + recursively` + ${nJSON_Sort_Test} 18 + +SectionEnd \ No newline at end of file diff --git a/agent/installer/ns_json/Examples/nsJSON/Syntax.nsi b/agent/installer/ns_json/Examples/nsJSON/Syntax.nsi new file mode 100644 index 00000000000..e231b277c8a --- /dev/null +++ b/agent/installer/ns_json/Examples/nsJSON/Syntax.nsi @@ -0,0 +1,35 @@ +!include MUI2.nsh + +Name `nsJSON plug-in` +OutFile nsJSON_Syntax.exe +RequestExecutionLevel user +ShowInstDetails show + +!insertmacro MUI_PAGE_INSTFILES + +!insertmacro MUI_LANGUAGE English + +!macro DoTest JSON Description + StrCpy $R0 `` + ClearErrors + nsJSON::Set /value `${JSON}` + nsJSON::Serialize + Pop $R0 + DetailPrint `${Description}:` + DetailPrint `${JSON} -> $R0` + IfErrors 0 +2 + DetailPrint `Error flag is set!` + DetailPrint `` +!macroend + +Section + + !insertmacro DoTest `{ "Input": [ { "test1": false, } ] }` `Trailing comma` + + !insertmacro DoTest `{ "Input": [ { "test1": false } .? ] }` `Junk characters` + + !insertmacro DoTest `{ "Input": [ { "test1": false } }` `Missing square bracket` + + !insertmacro DoTest `{ "Input": [ { "test1": false ] }` `Missing curly brace` + +SectionEnd \ No newline at end of file diff --git a/agent/installer/ns_json/Examples/nsJSON/UnicodeNSIS.nsi b/agent/installer/ns_json/Examples/nsJSON/UnicodeNSIS.nsi new file mode 100644 index 00000000000..96d91388bbb --- /dev/null +++ b/agent/installer/ns_json/Examples/nsJSON/UnicodeNSIS.nsi @@ -0,0 +1,25 @@ +!include MUI2.nsh + +Name `nsJSON plug-in` +OutFile nsJSON_UnicodeNSIS.exe +RequestExecutionLevel user +ShowInstDetails show +Unicode true + +!insertmacro MUI_PAGE_INSTFILES + +!insertmacro MUI_LANGUAGE English + +Section + + nsJSON::Set /tree testTree testNode /value testValue + + nsJSON::Get /tree testTree testNode /end + Pop $R0 + DetailPrint $R0 + + nsJSON::Serialize /tree testTree + Pop $R0 + DetailPrint $R0 + +SectionEnd \ No newline at end of file diff --git a/agent/installer/ns_json/Plugins/amd64-unicode/nsJSON.dll b/agent/installer/ns_json/Plugins/amd64-unicode/nsJSON.dll new file mode 100644 index 00000000000..6f0c48d2f62 Binary files /dev/null and b/agent/installer/ns_json/Plugins/amd64-unicode/nsJSON.dll differ diff --git a/agent/installer/ns_json/Plugins/x86-ansi/nsJSON.dll b/agent/installer/ns_json/Plugins/x86-ansi/nsJSON.dll new file mode 100644 index 00000000000..c11ede1f132 Binary files /dev/null and b/agent/installer/ns_json/Plugins/x86-ansi/nsJSON.dll differ diff --git a/agent/installer/ns_json/Plugins/x86-unicode/nsJSON.dll b/agent/installer/ns_json/Plugins/x86-unicode/nsJSON.dll new file mode 100644 index 00000000000..c7999466b2f Binary files /dev/null and b/agent/installer/ns_json/Plugins/x86-unicode/nsJSON.dll differ diff --git a/agent/installer/nsis_pcre/LICENSE b/agent/installer/nsis_pcre/LICENSE new file mode 100644 index 00000000000..1dfbcbfb06c --- /dev/null +++ b/agent/installer/nsis_pcre/LICENSE @@ -0,0 +1,45 @@ +// An NSIS plugin providing Perl compatible regular expression functions. +// +// A simple wrapper around the excellent PCRE library which was written by +// Philip Hazel, University of Cambridge. +// +// For those that require documentation on how to construct regular expressions, +// please see http://www.pcre.org/ +// +// _____________________________________________________________________________ +// +// Copyright (c) 2007 Computerway Business Solutions Ltd. +// Copyright (c) 2005 Google Inc. +// Copyright (c) 1997-2006 University of Cambridge +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the University of Cambridge nor the name of Google +// Inc. nor the name of Computerway Business Solutions Ltd. nor the names +// of their contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Core PCRE Library Written by: Philip Hazel, University of Cambridge +// C++ Wrapper functions by: Sanjay Ghemawat, Google Inc. +// Support for PCRE_XXX modifiers by: Giuseppe Maxia +// NSIS integration by: Rob Stocks, Computerway Business Solutions Ltd. diff --git a/agent/installer/nsis_pcre/NSISpcre.cpp b/agent/installer/nsis_pcre/NSISpcre.cpp new file mode 100644 index 00000000000..e787aba5667 --- /dev/null +++ b/agent/installer/nsis_pcre/NSISpcre.cpp @@ -0,0 +1,501 @@ +// An NSIS plugin providing Perl compatible regular expression functions. +// +// A simple wrapper around the excellent PCRE library which was written by +// Philip Hazel, University of Cambridge. +// +// For those that require documentation on how to construct regular expressions, +// please see http://www.pcre.org/ +// +// _____________________________________________________________________________ +// +// Copyright (c) 2007 Computerway Business Solutions Ltd. +// Copyright (c) 2005 Google Inc. +// Copyright (c) 1997-2006 University of Cambridge +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the University of Cambridge nor the name of Google +// Inc. nor the name of Computerway Business Solutions Ltd. nor the names +// of their contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Core PCRE Library Written by: Philip Hazel, University of Cambridge +// C++ Wrapper functions by: Sanjay Ghemawat, Google Inc. +// Support for PCRE_XXX modifiers by: Giuseppe Maxia +// NSIS integration by: Rob Stocks, Computerway Business Solutions Ltd. + +#include +#include +#include "exdll.h" +#include "pcre-7.0\pcre.h" +#include "pcre-7.0\pcrecpp.h" + +HINSTANCE g_hInstance; +HWND g_hwndParent; +pcrecpp::RE_Options g_options; +pcrecpp::RE *g_reFaC = NULL; +string g_inputFaC = ""; + +inline void pushint(int i) +{ + char intstr[32]; + sprintf(intstr, "%d", i); + pushstring(intstr); +} + +inline bool convertboolstr(string s) +{ + return (string("1").compare(s)==0) + || (string("true").compare(s)==0) + || (string("TRUE").compare(s)==0) + || (string("True").compare(s)==0); +} + +inline void ResetFind() +{ + if (g_reFaC!=NULL) + { + delete g_reFaC; + g_reFaC = NULL; + } +} + +void SetOrClearOption(string opt, bool set) +{ + if (string("CASELESS").compare(opt)==0) g_options.set_caseless(set); + if (string("MULTILINE").compare(opt)==0) g_options.set_multiline(set); + if (string("DOTALL").compare(opt)==0) g_options.set_dotall(set); + if (string("EXTENDED").compare(opt)==0) g_options.set_extended(set); + if (string("DOLLAR_ENDONLY").compare(opt)==0) g_options.set_dollar_endonly(set); + if (string("EXTRA").compare(opt)==0) g_options.set_extra(set); + if (string("UTF8").compare(opt)==0) g_options.set_utf8(set); + if (string("UNGREEDY").compare(opt)==0) g_options.set_ungreedy(set); + if (string("NO_AUTO_CAPTURE").compare(opt)==0) g_options.set_no_auto_capture(set); + if (string("i").compare(opt)==0) g_options.set_caseless(set); + if (string("m").compare(opt)==0) g_options.set_multiline(set); + if (string("s").compare(opt)==0) g_options.set_dotall(set); + if (string("x").compare(opt)==0) g_options.set_extended(set); +} + +bool PerformMatch(pcrecpp::RE *re, string *_subject, pcrecpp::RE::Anchor anchor, int stackoffset, bool requireCaptures) +{ + string* results = NULL; + int captures; + bool matched = false; + pcrecpp::StringPiece subject(*_subject); + + captures = re->NumberOfCapturingGroups(); + if (captures<0) captures = 0; + if (captures==0 && requireCaptures) + { + pushstring("error No capture groups specified in pattern."); + } + else + { + results = new string[captures]; + const pcrecpp::Arg* *args = new const pcrecpp::Arg*[captures]; + for (int i = 0; i < captures; i++) + { + args[i] = new pcrecpp::Arg(&results[i]); + } + int consumed; + matched = re->DoMatch(subject, anchor, &consumed, args, captures); + for (int i = 0; i < captures; i++) + { + delete args[i]; + } + delete[] args; + + if (matched) + { + subject.remove_prefix(consumed); + + char** savestack = NULL; + if (stackoffset>0) + { + savestack = new char*[stackoffset]; + for (int i = 0; i < stackoffset; i++) + { + savestack[i] = new char[g_stringsize]; + popstring(savestack[i]); + } + } + + for (int i = (captures-1); i >= 0; i--) + { + pushstring(results[i].c_str()); + } + + if (stackoffset>0) + { + for (int i = (stackoffset-1); i >= 0; i--) + { + pushstring(savestack[i]); + delete[] savestack[i]; + } + delete[] savestack; + } + + delete[] results; + } + + if (matched) pushint(captures); + pushstring((matched)?"true":"false"); + } + + subject.CopyToString(_subject); + + return matched; +} + + +BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved) +{ + g_hInstance=(HINSTANCE)hInst; + if (DLL_PROCESS_DETACH == ul_reason_for_call) + { + ResetFind(); + } + return TRUE; +} + + +extern "C" __declspec(dllexport) +void RECheckPattern(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra) +{ + g_hwndParent=hwndParent; + + EXDLL_INIT(); + + char* pattern = new char[string_size]; + + popstring(pattern); + + pcrecpp::RE re(pattern, g_options); + + string errorstr = re.error(); + + pushstring(errorstr.c_str()); + + delete[] pattern; +} + +extern "C" __declspec(dllexport) +void REQuoteMeta(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra) +{ + g_hwndParent=hwndParent; + + EXDLL_INIT(); + + char* toquote = new char[string_size]; + + popstring(toquote); + + string quoted = pcrecpp::RE::QuoteMeta(toquote); + + pushstring(quoted.c_str()); + + delete[] toquote; +} + + +extern "C" __declspec(dllexport) +void REFind(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra) +{ + g_hwndParent=hwndParent; + + EXDLL_INIT(); + + if (g_options.no_auto_capture()) + { + pushstring("error FindAndConsume called with NO_AUTO_CAPTURE"); + return; + } + + char* pattern = new char[string_size]; + char* subject = new char[string_size]; + char* stackoffsetstr = new char[string_size]; + int stackoffset = 0; + + popstring(pattern); + popstring(subject); + popstring(stackoffsetstr); + + if (strlen(stackoffsetstr)>0) + { + stackoffset = atoi(stackoffsetstr); + } + + ResetFind(); + + g_reFaC = new pcrecpp::RE(pattern, g_options); + g_inputFaC = (string)(subject); + + string errorstr = g_reFaC->error(); + + if (errorstr.empty()) + { + if (g_reFaC->NumberOfCapturingGroups()==0) + { + string newpattern = "("+g_reFaC->pattern()+")"; + delete g_reFaC; + g_reFaC = new pcrecpp::RE(newpattern, g_options); + } + PerformMatch(g_reFaC, &g_inputFaC, g_reFaC->UNANCHORED, stackoffset, true); + } + else + { + errorstr.insert(0, "error "); + pushstring(errorstr.c_str()); + } + + delete[] subject; + delete[] pattern; +} + +extern "C" __declspec(dllexport) +void REFindNext(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra) +{ + g_hwndParent=hwndParent; + + EXDLL_INIT(); + + char* stackoffsetstr = new char[string_size]; + int stackoffset = 0; + + popstring(stackoffsetstr); + + if (strlen(stackoffsetstr)>0) + { + stackoffset = atoi(stackoffsetstr); + } + + if (g_reFaC!=NULL) + { + PerformMatch(g_reFaC, &g_inputFaC, g_reFaC->UNANCHORED, stackoffset, true); + } + else + { + pushstring("error FindAndConsume must be called before FindAndConsumeNext."); + } + + delete[] stackoffsetstr; +} + +extern "C" __declspec(dllexport) +void REFindClose(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra) +{ + g_hwndParent=hwndParent; + + EXDLL_INIT(); + + ResetFind(); +} + +extern "C" __declspec(dllexport) +void REMatches(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra) +{ + g_hwndParent=hwndParent; + + EXDLL_INIT(); + + char* pattern = new char[string_size]; + char* subject = new char[string_size]; + char* partialstr = new char[string_size]; + char* stackoffsetstr = new char[string_size]; + int stackoffset = 0; + + popstring(pattern); + popstring(subject); + popstring(partialstr); + popstring(stackoffsetstr); + + if (strlen(stackoffsetstr)>0) + { + stackoffset = atoi(stackoffsetstr); + } + + pcrecpp::RE re(pattern, g_options); + + string errorstr = re.error(); + + if (errorstr.empty()) + { + string input(subject); + pcrecpp::RE::Anchor a = pcrecpp::RE::Anchor::ANCHOR_BOTH; + if (convertboolstr(partialstr) || g_options.multiline()) + a = pcrecpp::RE::Anchor::UNANCHORED; + PerformMatch(&re, &input, a, stackoffset, false); + } + else + { + errorstr.insert(0, "error "); + pushstring(errorstr.c_str()); + } + delete[] stackoffsetstr; + delete[] partialstr; + delete[] pattern; + delete[] subject; +} + +extern "C" __declspec(dllexport) +void REReplace(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra) +{ + g_hwndParent=hwndParent; + + EXDLL_INIT(); + + char* pattern = new char[string_size]; + char* subject = new char[string_size]; + char* replacement = new char[string_size]; + char* replaceall = new char[string_size]; + + popstring(pattern); + popstring(subject); + popstring(replacement); + popstring(replaceall); + + pcrecpp::RE re(pattern, g_options); + + string errorstr = re.error(); + if (errorstr.empty()) + { + string subj = (string)subject; + string replall = (string)replaceall; + bool success = false; + + if (convertboolstr(replall)) + { + success = (re.GlobalReplace(replacement, &subj)>0); + } + else + { + success = re.Replace(replacement, &subj); + } + + if (success) + { + pushstring(subj.c_str()); + pushstring("true"); + } + else + { + pushstring("false"); + } + } + else + { + errorstr.insert(0, "error "); + pushstring(errorstr.c_str()); + } + + delete[] replaceall; + delete[] replacement; + delete[] pattern; + delete[] subject; +} + +extern "C" __declspec(dllexport) +void REClearAllOptions(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra) +{ + g_hwndParent=hwndParent; + + EXDLL_INIT(); + + g_options.set_all_options(0); +} + +extern "C" __declspec(dllexport) +void REClearOption(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra) +{ + g_hwndParent=hwndParent; + + EXDLL_INIT(); + + char* pcreopt = new char[string_size]; + popstring(pcreopt); + + SetOrClearOption(pcreopt, false); + + delete[] pcreopt; +} + +extern "C" __declspec(dllexport) +void RESetOption(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra) +{ + g_hwndParent=hwndParent; + + EXDLL_INIT(); + + char* pcreopt = new char[string_size]; + popstring(pcreopt); + + SetOrClearOption(pcreopt, true); + + delete[] pcreopt; +} + +extern "C" __declspec(dllexport) +void REGetOption(HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters *extra) +{ + g_hwndParent=hwndParent; + + EXDLL_INIT(); + + char* pcreopt = new char[string_size]; + bool set = false; + + popstring(pcreopt); + + if (string("CASELESS").compare(pcreopt)==0) + set = g_options.caseless(); + else if (string("MULTILINE").compare(pcreopt)==0) + set = g_options.multiline(); + else if (string("DOTALL").compare(pcreopt)==0) + set = g_options.dotall(); + else if (string("EXTENDED").compare(pcreopt)==0) + set = g_options.extended(); + else if (string("DOLLAR_ENDONLY").compare(pcreopt)==0) + set = g_options.dollar_endonly(); + else if (string("EXTRA").compare(pcreopt)==0) + set = g_options.extra(); + else if (string("UTF8").compare(pcreopt)==0) + set = g_options.utf8(); + else if (string("UNGREEDY").compare(pcreopt)==0) + set = g_options.ungreedy(); + else if (string("NO_AUTO_CAPTURE").compare(pcreopt)==0) + set = g_options.no_auto_capture(); + else if (string("i").compare(pcreopt)==0) + set = g_options.caseless(); + else if (string("m").compare(pcreopt)==0) + set = g_options.multiline(); + else if (string("s").compare(pcreopt)==0) + set = g_options.dotall(); + else if (string("x").compare(pcreopt)==0) + set = g_options.extended(); + + delete[] pcreopt; + + pushstring(set?"true":"false"); +} + diff --git a/agent/installer/nsis_pcre/NSISpcre.dll b/agent/installer/nsis_pcre/NSISpcre.dll new file mode 100644 index 00000000000..6bcfada4141 Binary files /dev/null and b/agent/installer/nsis_pcre/NSISpcre.dll differ diff --git a/agent/installer/nsis_pcre/NSISpcre.nsh b/agent/installer/nsis_pcre/NSISpcre.nsh new file mode 100644 index 00000000000..cc87299f848 --- /dev/null +++ b/agent/installer/nsis_pcre/NSISpcre.nsh @@ -0,0 +1,1070 @@ +/* +_____________________________________________________________________________ + + PCRE Functions Header v1.0 +_____________________________________________________________________________ + +An NSIS plugin providing Perl compatible regular expression functions. + +A simple wrapper around the excellent PCRE library which was written by +Philip Hazel, University of Cambridge. + +For those that require documentation on how to construct regular expressions, +please see http://www.pcre.org/ + +_____________________________________________________________________________ + +Copyright (c) 2007 Computerway Business Solutions Ltd. +Copyright (c) 2005 Google Inc. +Copyright (c) 1997-2006 University of Cambridge + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the University of Cambridge nor the name of Google + Inc. nor the name of Computerway Business Solutions Ltd. nor the names + of their contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +Core PCRE Library Written by: Philip Hazel, University of Cambridge +C++ Wrapper functions by: Sanjay Ghemawat, Google Inc. +Support for PCRE_XXX modifiers by: Giuseppe Maxia +NSIS integration by: Rob Stocks, Computerway Business Solutions Ltd. + +_____________________________________________________________________________ + +Usage: +====== + + ... + # include this header + !include NSISpcre.nsh + ... + # include any functions that will be used in the installer + !insertmacro RESetOption + !insertmacro REClearOption + !insertmacro REGetOption + !insertmacro REClearAllOptions + !insertmacro REMatches + !insertmacro RECaptureMatches + !insertmacro REReplace + ... + # include any functions that will be used in the uninstaller + !insertmacro un.RESetOption + !insertmacro un.REClearOption + !insertmacro un.REGetOption + !insertmacro un.REClearAllOptions + !insertmacro un.REMatches + !insertmacro un.RECaptureMatches + !insertmacro un.REReplace + ... + # Use a function or integrate with LogicLib + Section|Function ... + ... + ${REMatches} $0 ^A(.*)Z" "ABC...XYZ" 0 + ... + ${If} "subject" =~ "pattern" + ... + ${EndIf} + ... + SectionEnd|FunctionEnd + ... + + See NSISpcreTest.nsi for examples. + +LogicLib Integration: +===================== + + By including this header, two additional string "operators" are added to LogicLib + as follows: + + a =~ b Test if subject a matches pattern b + a !~ b Test if subject a does not match pattern b + + E.g. + + ${If} $0 =~ ".*\\" + # $0 has a trailing backslash + ${Else} + # $0 does not have a trailing backslash + ${EndIf} + + ${If} $0 !~ "http://.*" + # $0 does not start "http://" + ${Else} + # $0 does start with "http://" + ${EndIf} + + You must insert the REMatches function in order to use these "operators" with: + + !insertmacro REMatches + or + !insertmacro un.REMatches + + To integrate with LogicLib in the uninstaller, prefix the operators with 'un.' + as follows: + + ${If} $0 un.=~ ".*\\" + ... + ${EndIf} + +Available Functions: +==================== + + RECheckPattern RESULT PATTERN + + Checks whether the supplied regular expression string is valid. + + E.g. ${RECheckPattern} $0 ".*" + # Will return "" becasue the pattern is valid + ${RECheckPattern} $0 "(.*" + # Will return an error because of the unmatched bracket + + Params: + + RESULT (output) + + The result of the test. An empty string if PATTERN is ok otherwise a + description of what was wrong with it. + + PATTERN (input) + + See REMatches. + + Notes: + + Unlike the other functions, this function does not set the error flag if + the supplied PATTERN is invalid. + + REQuoteMeta RESULT SUBJECT + + Escapes characters in the subject so the entire string will be interpreted + literally. + + E.g. ${REQuoteMeta} $0 ".*" + # Will return "\.\*" + + Params: + + RESULT (output) + + The converted from of SUBJECT with special characters escaped. + + SUBJECT (input) + + The string to convert. + + REMatches RESULT PATTERN SUBJECT PARTIAL + + Test whether a string matches a regular expression. + + E.g. ${REMatches} $0 "A(.*)Z" "ABC...XYZ" 0 + # Will return "true" + ${REMatches} $0 "A(.*)" "ABC...XYZ" 0 + # Will return "false" because partial matching wasn't requested + ${REMatches} $0 "A(.*)" "ABC...XYZ" 1 + # Will return "true" because partial matching was requested + + Params: + + RESULT (output) + + The result of the test. After the call, the return variable will contain + one of the following values: + "true" The string in SUBJECT matches the PATTERN + "false" The string in SUBJECT does not match the PATTERN + "error " There was an error compiling the PATTERN. The + error text will be returned after the word error. + The error flag will be set in this case. + + PATTERN (input) + + The PCRE-compatible regular expression to check for (without the leading + and trailing slashes and without any options). E.g. '.+' (not '/.+/s'). + See http://www.pcre.org/ for documentation & examples. + + SUBJECT (input) + + The string to test. + + PARTIAL (input) + + Either 1 or 0. Pass the value 1 to enable partial matches (part of the + SUBJECT string must match the PATTERN string) or 0 to force full matches + (the whole SUBJECT string must match the PATTERN string). + + Notes: + + See SetOptions for more control over pattern matching (e.g. case sensitivity). + The PARTIAL option is ignored if in multiline mode. + + RECaptureMatches RESULT PATTERN SUBJECT PARTIAL + + Test whether a string matches a regular expression and return any substrings + captured. + + E.g. ${RECaptureMatches} $0 "([^=]+)=(.+)" "pcre=excellent" + # Will return 2 in $0 because 2 strings were captured + Pop $1 # Will contain "pcre" + Pop $2 # Will contain "excellent" + + Params: + + RESULT (output) + + The string "false" if SUBJECT does not match PATTERN. + The number of substrings captured by capture groups if SUBJECT does match + PATTERN. + The string "error" followed by an error message if there was a problem + compiling PATTERN (the error flag will be set in this case). + + PATTERN (input) + + See REMatches. + + SUBJECT (input) + + See REMatches. + + PARTIAL (input) + + See REMatches. + + Notes: + + This function is the same as REMatches except that if SUBJECT matches PATTERN, + the number of substring captured is returned instead of the string "true". Also, + each captured string is available on the stack in left-to-right order of capture. + To use this function, first read the RESULT. If the error flag is not set and + RESULT is not "false", read it as an integer and pop that number of values from + the stack (these will be the captured substrings). + + This function can return 0 on a successful match indicating that SUBJECT matches + the PATTERN but that no substrings were captured (e.g. because no capture groups + were specified or because the NO_AUTO_CAPTURE option was set). + + REFind RESULT PATTERN SUBJECT + REFindNext RESULT + REFindClose + + Extracts captured substrings from SUBJECT according to PATTERN and advances the + position in SUBJECT so subsequent calls to REFindNext will obtain the next set + of captured substrings. + + E.g. ${REFind} "([0-9]+)" "123 456" + # Will capture "123" + ${REFindNext} + # Will capture "456" + ${REFindClose} + + Params: + + RESULT (output) + + Does not apply to REFindClose which has no parameters. + See RECaptureMatches. + For REFindNext, RESULT will be "false" if there were no more matches. + + PATTERN (input) + + Only applies to REFind. + See REMatches. + + SUBJECT (input) + + Only applies to REFind. + See REMatches. + + Notes: + + Partial matching is always enabled. + Not compatible with the NO_AUTO_CAPTURE option (see RESetOption). + PATTERNS containing no capture groups will be bracketed to create a single + capture group that matches the entire pattern. + REFindClose must be called to free resources in the plugin. It may only be + omitted if REFind is called again since this will automatically free any + resources allocated by a previous call to REFind. + + REReplace RESULT PATTERN SUBJECT REPLACEMENT REPLACEALL + + Replaces one or all occurances of PATTERN found in SUBJECT with REPLACEMENT. + + E.g. ${REReplace} $0 "h(.*)" "hello world!" "H\1" 0 + + Params: + + RESULT (output) + + The SUBJECT string with any replacements made. If no matches of PATTERN were + found in SUBJECT, an empty string will be returned. If there was an error + compiling PATTERN, the error flag will be set and the error will be returned. + + PATTERN (input) + + See REMatches. The regular expression to search for. Up to 9 captured substrings + can be referenced (by number 1-9) in the REPLACEMENT string if required. + + SUBJECT (input) + + The string on which to perform the replacements. + + REPLACEMENT (input) + + The string to replace occurances of PATTERN with. This string may refer to up to + 9 captured substrings defined in PATTERN by using '\1' to '\9'. + + REPLACEALL + + Either 0 or 1. To replace only the first occurance of PATTERN in SUBJECT with + REPLACEMENT, specify 0. To replace all occurances, specify 1. + + REClearAllOptions + + Clears all options and reverts to default PCRE pattern matching behaviour. + + E.g. ${REClearAllOptions} + + Params: + + No parameters. + + Notes: + + See RESetOption for a list of available options. + + RESetOption OPTION + + Sets the option specified in OPTION (turns it on). + + E.g. ${RESetOption} "CASELESS" + + Params: + + OPTION (input) + + The option to set. One of the following strings: + + CASELESS + Perform case-insensitive matching + MULTILINE + Enable matching of individual lines. '^' and '$' can be used to + match the starts and ends of lines instead of the start and end + of the subject string. Forces partial matching. + DOTALL + Allow '.' to match newlines within the subject. + EXTENDED + Ignore whitespace & comments in patterns + DOLLAR_ENDONLY + When not in multiline mode, force '$' to match only the end of the + entire string (otherwise it will also match prior to the last + newline if that newline terminates the string) + EXTRA + See PCRE documentation. + UTF8 + Enable UTF8 handling (untested from NSIS). + UNGREEDY + Set quantifiers to be ungreedy by default instead of greedy. This + also reverses the meaning of the '?' ungreedy qualifier to mean + greedy. + NO_AUTO_CAPTURE + Don't capture subgroups. + m + Synonym for MULTILINE (Perl syntax). + i + Synonym for CASELESS (Perl syntax). + s + Synonym for DOTALL (Perl syntax). + x + Synonym for EXTENDED (Perl syntax). + + Notes: + + Once set, the option will apply to all further calls until cleared. + + REClearOption OPTION + + Clears the option specified in OPTION (turns it off). + + E.g. ${REClearOption} "CASELESS" + + Params: + + OPTION (input) + + See RESetOption. + + Notes: + + Once cleared, the option will not apply to all further calls until set. + + REGetOption RESULT OPTION + + Obtains the current state of the specified OPTION. + + E.g. ${REGetOption} $0 "CASELESS" + + Params: + + RESULT (output) + + The state of the option: "true" if set and "false" otherwise. + + OPTION (input) + + See RESetOption. + +_____________________________________________________________________________ + +*/ + +!ifndef PCRELIB_INCLUDED +!define PCRELIB_INCLUDED + +!define _PCRELIB_UN + +!include LogicLib.nsh + +# Macros + +!macro RECheckPatternCall RESULT PATTERN + Push `${PATTERN}` + Call RECheckPattern + Pop ${RESULT} +!macroend + +!macro un.RECheckPatternCall RESULT PATTERN + Push `${PATTERN}` + Call un.RECheckPattern + Pop ${RESULT} +!macroend + +!macro REQuoteMetaCall RESULT SUBJECT + Push `${SUBJECT}` + Call REQuoteMeta + Pop ${RESULT} +!macroend + +!macro un.REQuoteMetaCall RESULT SUBJECT + Push `${SUBJECT}` + Call un.REQuoteMeta + Pop ${RESULT} +!macroend + +!macro REClearAllOptionsCall + Call REClearAllOptions +!macroend + +!macro un.REClearAllOptionsCall + Call un.REClearAllOptions +!macroend + +!macro REClearOptionCall OPTION + Push `${OPTION}` + Call REClearOption +!macroend + +!macro un.REClearOptionCall OPTION + Push `${OPTION}` + Call un.REClearOption +!macroend + +!macro RESetOptionCall OPTION + Push `${OPTION}` + Call RESetOption +!macroend + +!macro un.RESetOptionCall OPTION + Push `${OPTION}` + Call un.RESetOption +!macroend + +!macro REGetOptionCall RESULT OPTION + Push `${OPTION}` + Call REGetOption + Pop ${RESULT} +!macroend + +!macro un.REGetOptionCall RESULT OPTION + Push `${OPTION}` + Call un.REGetOption + Pop ${RESULT} +!macroend + +!macro REMatchesCall RESULT PATTERN SUBJECT PARTIAL + Push `${PATTERN}` + Push `${SUBJECT}` + Push `${PARTIAL}` + Push "0" + Call REMatches + Pop ${RESULT} +!macroend + +!macro un.REMatchesCall RESULT PATTERN SUBJECT PARTIAL + Push `${PATTERN}` + Push `${SUBJECT}` + Push `${PARTIAL}` + Push "0" + Call un.REMatches + Pop ${RESULT} +!macroend + +!macro RECaptureMatchesCall RESULT PATTERN SUBJECT PARTIAL + Push `${PATTERN}` + Push `${SUBJECT}` + Push `${PARTIAL}` + Push "1" + Call REMatches + Pop ${RESULT} +!macroend + +!macro un.RECaptureMatchesCall RESULT PATTERN SUBJECT PARTIAL + Push `${PATTERN}` + Push `${SUBJECT}` + Push `${PARTIAL}` + Push "1" + Call un.REMatches + Pop ${RESULT} +!macroend + +!macro REFindCall RESULT PATTERN SUBJECT + Push `${PATTERN}` + Push `${SUBJECT}` + Call REFind + Pop ${RESULT} +!macroend + +!macro un.REFindCall RESULT PATTERN SUBJECT + Push `${PATTERN}` + Push `${SUBJECT}` + Call un.REFind + Pop ${RESULT} +!macroend + +!macro REFindNextCall RESULT + Call REFindNext + Pop ${RESULT} +!macroend + +!macro un.REFindNextCall RESULT + Call un.REFindNext + Pop ${RESULT} +!macroend + +!macro REFindCloseCall + Call REFindClose +!macroend + +!macro un.REFindCloseCall + Call un.REFindClose +!macroend + +!macro REReplaceCall RESULT PATTERN SUBJECT REPLACEMENT REPLACEALL + Push `${PATTERN}` + Push `${SUBJECT}` + Push `${REPLACEMENT}` + Push `${REPLACEALL}` + Call REReplace + Pop ${RESULT} +!macroend + +!macro un.REReplaceCall RESULT PATTERN SUBJECT REPLACEMENT REPLACEALL + Push `${PATTERN}` + Push `${SUBJECT}` + Push `${REPLACEMENT}` + Push `${REPLACEALL}` + Call un.REReplace + Pop ${RESULT} +!macroend + +# Functions + +!macro RECheckPattern + !ifndef ${_PCRELIB_UN}RECheckPattern + !define ${_PCRELIB_UN}RECheckPattern `!insertmacro ${_PCRELIB_UN}RECheckPatternCall` + Function ${_PCRELIB_UN}RECheckPattern + + Exch $0 + + NSISpcre::RECheckPattern /NOUNLOAD $0 + + Pop $0 + + Exch $0 + + FunctionEnd + !endif +!macroend + +!macro REQuoteMeta + !ifndef ${_PCRELIB_UN}REQuoteMeta + !define ${_PCRELIB_UN}REQuoteMeta `!insertmacro ${_PCRELIB_UN}REQuoteMetaCall` + Function ${_PCRELIB_UN}REQuoteMeta + + Exch $0 + + NSISpcre::REQuoteMeta /NOUNLOAD $0 + + Pop $0 + + Exch $0 + + FunctionEnd + !endif +!macroend + +!macro REClearAllOptions + !ifndef ${_PCRELIB_UN}REClearAllOptions + !define ${_PCRELIB_UN}REClearAllOptions `!insertmacro ${_PCRELIB_UN}REClearAllOptionsCall` + Function ${_PCRELIB_UN}REClearAllOptions + + NSISpcre::REClearAllOptions /NOUNLOAD + + FunctionEnd + !endif +!macroend + +!macro REClearOption + !ifndef ${_PCRELIB_UN}REClearOption + !define ${_PCRELIB_UN}REClearOption `!insertmacro ${_PCRELIB_UN}REClearOptionCall` + Function ${_PCRELIB_UN}REClearOption + + # [OPTION] + Exch $0 + + NSISpcre::REClearOption /NOUNLOAD $0 + + Pop $0 + + FunctionEnd + !endif +!macroend + +!macro RESetOption + !ifndef ${_PCRELIB_UN}RESetOption + !define ${_PCRELIB_UN}RESetOption `!insertmacro ${_PCRELIB_UN}RESetOptionCall` + Function ${_PCRELIB_UN}RESetOption + + # [OPTION] + Exch $0 + + NSISpcre::RESetOption /NOUNLOAD $0 + + Pop $0 + + FunctionEnd + !endif +!macroend + +!macro REGetOption + !ifndef ${_PCRELIB_UN}REGetOption + !define ${_PCRELIB_UN}REGetOption `!insertmacro ${_PCRELIB_UN}REGetOptionCall` + Function ${_PCRELIB_UN}REGetOption + + # [OPTION] + Exch $0 + + NSISpcre::REGetOption /NOUNLOAD $0 + + Pop $0 + + Exch $0 # [RESULT] + + FunctionEnd + !endif +!macroend + +!macro REMatches + !ifndef ${_PCRELIB_UN}REMatches + !define ${_PCRELIB_UN}REMatches `!insertmacro ${_PCRELIB_UN}REMatchesCall` + !define ${_PCRELIB_UN}RECaptureMatches `!insertmacro ${_PCRELIB_UN}RECaptureMatchesCall` + Function ${_PCRELIB_UN}REMatches + + # [PATTERN, SUBJECT, PARTIAL, CAPTURE] + Exch $0 # [PATTERN, SUBJECT, PARTIAL, $0] + Exch 3 # [$0, SUBJECT, PARTIAL, PATTERN] + Exch $1 # [$0, SUBJECT, PARTIAL, $1] + Exch 2 # [$0, $1, PARTIAL, SUBJECT] + Exch $2 # [$0, $1, PARTIAL, $2] + Exch # [$0, $1, $2, PARTIAL] + Exch $3 # [$0, $1, $2, $3] + Push $4 + + ${If} $0 != 0 + StrCpy $4 5 # Push captured strings under the 5 items at the top of the stack + ${Else} + StrCpy $4 0 # Push captured strings to the top of the stack + ${EndIf} + + NSISpcre::REMatches /NOUNLOAD $1 $2 $3 $4 + Pop $1 # true, false or error + ClearErrors + ${If} $1 == "true" + Pop $1 # Number of captured patterns + ${If} $0 != 0 + # Capturing so leave captured strings on stack + # Returned value is number of captured strings + ${Else} + # Remove captured strings from the stack + # Returned value is 'true' + ${For} $2 1 $1 + Pop $3 + ${Next} + StrCpy $1 "true" + ${EndIf} + ${ElseIf} $1 == "false" + # Do nothing - just return 'false' + ${Else} + SetErrors + ${EndIf} + + StrCpy $0 $1 + + Pop $4 + Pop $3 + Pop $2 + Pop $1 + Exch $0 + + FunctionEnd + !endif +!macroend + +!macro REFind + !ifndef ${_PCRELIB_UN}REFind + !define ${_PCRELIB_UN}REFind `!insertmacro ${_PCRELIB_UN}REFindCall` + Function ${_PCRELIB_UN}REFind + + # [PATTERN, SUBJECT] + Exch $0 # [PATTERN, $0] + Exch # [$0, PATTERN] + Exch $1 # [$0, $1] + + NSISpcre::REFind /NOUNLOAD $1 $0 2 + Pop $0 # true, false or error + ClearErrors + ${If} $0 == "true" + Pop $0 # Number of captured patterns + # Leave captured strings on stack + # Returned value is number of captured strings + ${ElseIf} $0 == "false" + # Do nothing - just return 'false' + ${Else} + SetErrors + ${EndIf} + + Pop $1 + Exch $0 + + FunctionEnd + !endif + !ifndef ${_PCRELIB_UN}REFindClose + !define ${_PCRELIB_UN}REFindClose `!insertmacro ${_PCRELIB_UN}REFindCloseCall` + Function ${_PCRELIB_UN}REFindClose + + NSISpcre::REFindClose /NOUNLOAD + + FunctionEnd + !endif +!macroend + +!macro REFindNext + !ifndef ${_PCRELIB_UN}REFindNext + !define ${_PCRELIB_UN}REFindNext `!insertmacro ${_PCRELIB_UN}REFindNextCall` + Function ${_PCRELIB_UN}REFindNext + + Push $0 + + NSISpcre::REFindNext /NOUNLOAD 1 + Pop $0 # true, false or error + ClearErrors + ${If} $0 == "true" + Pop $0 # Number of captured patterns + # Leave captured strings on stack + # Returned value is number of captured strings + ${ElseIf} $0 == "false" + # Do nothing - just return 'false' + ${Else} + SetErrors + ${EndIf} + + Exch $0 + + FunctionEnd + !endif +!macroend + +!macro REReplace + !ifndef ${_PCRELIB_UN}REReplace + !define ${_PCRELIB_UN}REReplace `!insertmacro ${_PCRELIB_UN}REReplaceCall` + Function ${_PCRELIB_UN}REReplace + + # [PATTERN, SUBJECT, REPLACEMENT, REPLACEALL] + Exch $0 # [PATTERN, SUBJECT, REPLACEMENT, $0] + Exch 3 # [$0, SUBJECT, REPLACEMENT, PATTERN] + Exch $1 # [$0, SUBJECT, REPLACEMENT, $1] + Exch 2 # [$0, $1, REPLACEMENT, SUBJECT] + Exch $2 # [$0, $1, REPLACEMENT, $2] + Exch # [$0, $1, $2, REPLACEMENT] + Exch $3 # [$0, $1, $2, $3] + + NSISpcre::REReplace /NOUNLOAD $1 $2 $3 $0 + Pop $1 # true, false or error + ClearErrors + ${If} $1 == "true" + Pop $0 # String with substitutions + ${ElseIf} $1 == "false" + StrCpy $0 "" + ${Else} + SetErrors + StrCpy $0 $1 + ${EndIf} + + Pop $3 + Pop $2 + Pop $1 + Exch $0 + + FunctionEnd + !endif +!macroend + +# LogicLib support (add =~ and !~ operators to LogicLib) +!macro _=~ _a _b _t _f + !define _t=${_t} + !ifdef _t= ; If no true label then make one + !define __t _LogicLib_Label_${__LINE__} + !else + !define __t ${_t} + !endif + + Push $0 + ${REMatches} $0 ${_b} ${_a} 1 + StrCmp $0 "true" +1 +3 + Pop $0 + Goto ${__t} + + Pop $0 + !define _f=${_f} + !ifndef _f= ; If a false label then go there + Goto ${_f} + !endif + !undef _f=${_f} + + !ifdef _t= ; If we made our own true label then place it + ${__t}: + !endif + !undef __t + !undef _t=${_t} +!macroend + +!macro _!~ _a _b _t _f + !define _t=${_t} + !ifdef _t= ; If no true label then make one + !define __t _LogicLib_Label_${__LINE__} + !else + !define __t ${_t} + !endif + + Push $0 + !ifdef PCRELLUN + ${un.REMatches} $0 ${_b} ${_a} 1 + !else + ${REMatches} $0 ${_b} ${_a} 1 + !endif + StrCmp $0 "true" +3 +1 + Pop $0 + Goto ${__t} + + Pop $0 + !define _f=${_f} + !ifndef _f= ; If a false label then go there + Goto ${_f} + !endif + !undef _f=${_f} + + !ifdef _t= ; If we made our own true label then place it + ${__t}: + !endif + !undef __t + !undef _t=${_t} +!macroend + +# Uninstaller support + +!macro un.RECheckPattern + !ifndef un.RECheckPattern + !undef _PCRELIB_UN + !define _PCRELIB_UN `un.` + + !insertmacro RECheckPattern + + !undef _PCRELIB_UN + !define _PCRELIB_UN + !endif +!macroend + +!macro un.REQuoteMeta + !ifndef un.REQuoteMeta + !undef _PCRELIB_UN + !define _PCRELIB_UN `un.` + + !insertmacro REQuoteMeta + + !undef _PCRELIB_UN + !define _PCRELIB_UN + !endif +!macroend + +!macro un.REClearAllOptions + !ifndef un.REClearAllOptions + !undef _PCRELIB_UN + !define _PCRELIB_UN `un.` + + !insertmacro REClearAllOptions + + !undef _PCRELIB_UN + !define _PCRELIB_UN + !endif +!macroend + +!macro un.REClearOption + !ifndef un.REClearOption + !undef _PCRELIB_UN + !define _PCRELIB_UN `un.` + + !insertmacro REClearOption + + !undef _PCRELIB_UN + !define _PCRELIB_UN + !endif +!macroend + +!macro un.RESetOption + !ifndef un.RESetOption + !undef _PCRELIB_UN + !define _PCRELIB_UN `un.` + + !insertmacro RESetOption + + !undef _PCRELIB_UN + !define _PCRELIB_UN + !endif +!macroend + +!macro un.REGetOption + !ifndef un.REGetOption + !undef _PCRELIB_UN + !define _PCRELIB_UN `un.` + + !insertmacro REGetOption + + !undef _PCRELIB_UN + !define _PCRELIB_UN + !endif +!macroend + +!macro un.REMatches + !ifndef un.REMatches + !undef _PCRELIB_UN + !define _PCRELIB_UN `un.` + + !insertmacro REMatches + + !undef _PCRELIB_UN + !define _PCRELIB_UN + !endif +!macroend + +!macro un.RECaptureMatches + !ifndef un.RECaptureMatches + !undef _PCRELIB_UN + !define _PCRELIB_UN `un.` + + !insertmacro RECaptureMatches + + !undef _PCRELIB_UN + !define _PCRELIB_UN + !endif +!macroend + +!macro un.REFind + !ifndef un.REFind + !undef _PCRELIB_UN + !define _PCRELIB_UN `un.` + + !insertmacro REFind + + !undef _PCRELIB_UN + !define _PCRELIB_UN + !endif +!macroend + +!macro un.REFindNext + !ifndef un.REFindNext + !undef _PCRELIB_UN + !define _PCRELIB_UN `un.` + + !insertmacro REFindNext + + !undef _PCRELIB_UN + !define _PCRELIB_UN + !endif +!macroend + +!macro un.REFindClose + !ifndef un.REFindClose + !undef _PCRELIB_UN + !define _PCRELIB_UN `un.` + + !insertmacro REFindClose + + !undef _PCRELIB_UN + !define _PCRELIB_UN + !endif +!macroend + +!macro un.REReplace + !ifndef un.REReplace + !undef _PCRELIB_UN + !define _PCRELIB_UN `un.` + + !insertmacro REReplace + + !undef _PCRELIB_UN + !define _PCRELIB_UN + !endif +!macroend + +!macro _un.=~ _a _b _t _f + !define PCRELLUN + !insertmacro _=~ `${_a}` `${_b}` `${_t}` `${_f}` + !undef PCRELLUN +!macroend + +!macro _un.!~ _a _b _t _f + !define PCRELLUN + !insertmacro _!~ `${_a}` `${_b}` `${_t}` `${_f}` + !undef PCRELLUN +!macroend + +!endif + diff --git a/agent/installer/nsis_pcre/NSISpcre.sln b/agent/installer/nsis_pcre/NSISpcre.sln new file mode 100644 index 00000000000..c15d1f35d6e --- /dev/null +++ b/agent/installer/nsis_pcre/NSISpcre.sln @@ -0,0 +1,29 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NSISpcre", "NSISpcre.vcproj", "{CE8CB3BC-A91C-4240-84B9-76FC5BC2B257}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dftables", "dftables\dftables.vcproj", "{28A109A2-C14B-4428-A6E3-6AB0CD7FDF17}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {CE8CB3BC-A91C-4240-84B9-76FC5BC2B257}.Debug.ActiveCfg = Debug|Win32 + {CE8CB3BC-A91C-4240-84B9-76FC5BC2B257}.Debug.Build.0 = Debug|Win32 + {CE8CB3BC-A91C-4240-84B9-76FC5BC2B257}.Release.ActiveCfg = Release|Win32 + {CE8CB3BC-A91C-4240-84B9-76FC5BC2B257}.Release.Build.0 = Release|Win32 + {28A109A2-C14B-4428-A6E3-6AB0CD7FDF17}.Debug.ActiveCfg = Debug|Win32 + {28A109A2-C14B-4428-A6E3-6AB0CD7FDF17}.Debug.Build.0 = Debug|Win32 + {28A109A2-C14B-4428-A6E3-6AB0CD7FDF17}.Release.ActiveCfg = Release|Win32 + {28A109A2-C14B-4428-A6E3-6AB0CD7FDF17}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/agent/installer/nsis_pcre/NSISpcre.vcproj b/agent/installer/nsis_pcre/NSISpcre.vcproj new file mode 100644 index 00000000000..f1e7fb2211a --- /dev/null +++ b/agent/installer/nsis_pcre/NSISpcre.vcproj @@ -0,0 +1,227 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/agent/installer/nsis_pcre/NSISpcreTest.nsi b/agent/installer/nsis_pcre/NSISpcreTest.nsi new file mode 100644 index 00000000000..0d520a32151 --- /dev/null +++ b/agent/installer/nsis_pcre/NSISpcreTest.nsi @@ -0,0 +1,531 @@ +;_____________________________________________________________________________ +; +; PCRE Functions Test +;_____________________________________________________________________________ +; +; 2007 Rob Stocks, Computerway Business Solutions Ltd. + +Name "PCRE Functions Test" +OutFile "PCREFuncTest.exe" +Caption "$(^Name)" +ShowInstDetails show +XPStyle on + +Var FUNCTION +Var OUT +Var STACKTOP + +!include "NSISpcre.nsh" +!insertmacro REQuoteMeta +!insertmacro RECheckPattern +!insertmacro REClearAllOptions +!insertmacro REClearOption +!insertmacro REGetOption +!insertmacro RESetOption +!insertmacro REMatches +!insertmacro REReplace +!insertmacro REFind +!insertmacro REFindNext + +!insertmacro un.REGetOption +!insertmacro un.RESetOption +!insertmacro un.REClearOption +!insertmacro un.REClearAllOptions +!insertmacro un.REMatches +!insertmacro un.REReplace + +;############### INSTALL ############### + +!define StackVerificationStart `!insertmacro StackVerificationStart` +!macro StackVerificationStart _FUNCTION + StrCpy $FUNCTION ${_FUNCTION} + Call StackVerificationStart +!macroend + +!define StackVerificationEnd `!insertmacro StackVerificationEnd` +!macro StackVerificationEnd + Call StackVerificationEnd +!macroend + +Function StackVerificationStart + StrCpy $0 !0 + StrCpy $1 !1 + StrCpy $2 !2 + StrCpy $3 !3 + StrCpy $4 !4 + StrCpy $5 !5 + StrCpy $6 !6 + StrCpy $7 !7 + StrCpy $8 !8 + StrCpy $9 !9 + StrCpy $R0 !R0 + StrCpy $R1 !R1 + StrCpy $R2 !R2 + StrCpy $R3 !R3 + StrCpy $R4 !R4 + StrCpy $R5 !R5 + StrCpy $R6 !R6 + StrCpy $R7 !R7 + StrCpy $R8 !R8 + StrCpy $R9 !R9 + + Push "StackVerification" +FunctionEnd + +Function StackVerificationEnd + IfErrors +3 + DetailPrint 'PASSED $FUNCTION no errors' + goto +2 + DetailPrint '*** FAILED $FUNCTION error' + + Pop $STACKTOP + StrCmp $STACKTOP 'StackVerification' 0 stackerror + #DetailPrint 'PASSED $FUNCTION stack' + + goto +2 + stackerror: + DetailPrint '*** FAILED $FUNCTION stack ($STACKTOP)' + + StrCmp $0 '!0' 0 regerror + StrCmp $1 '!1' 0 regerror + StrCmp $2 '!2' 0 regerror + StrCmp $3 '!3' 0 regerror + StrCmp $4 '!4' 0 regerror + StrCmp $5 '!5' 0 regerror + StrCmp $6 '!6' 0 regerror + StrCmp $7 '!7' 0 regerror + StrCmp $8 '!8' 0 regerror + StrCmp $9 '!9' 0 regerror + StrCmp $R0 '!R0' 0 regerror + StrCmp $R1 '!R1' 0 regerror + StrCmp $R2 '!R2' 0 regerror + StrCmp $R3 '!R3' 0 regerror + StrCmp $R4 '!R4' 0 regerror + StrCmp $R5 '!R5' 0 regerror + StrCmp $R6 '!R6' 0 regerror + StrCmp $R7 '!R7' 0 regerror + StrCmp $R8 '!R8' 0 regerror + StrCmp $R9 '!R9' 0 regerror + #DetailPrint 'PASSED $FUNCTION registers' + goto end + + regerror: + DetailPrint '*** FAILED $FUNCTION registers' +; MessageBox MB_OKCANCEL '$$0={$0}$\n$$1={$1}$\n$$2={$2}$\n$$3={$3}$\n$$4={$4}$\n$$5={$5}$\n$$6={$6}$\n$$7={$7}$\n$$8={$8}$\n$$9={$9}$\n$$R0={$R0}$\n$$R1={$R1}$\n$$R2={$R2}$\n$$R3={$R3}$\n$$R4={$R4}$\n$$R5={$R5}$\n$$R6={$R6}$\n$$R7={$R7}$\n$$R8={$R8}$\n$$R9={$R9}' IDOK +2 +; quit + + end: +FunctionEnd + +Section LogicLibIntegration + + ${StackVerificationStart} LogicLibIntegration + + Push $0 + StrCpy $0 "c:\Program Files\" + ${If} $0 !~ ".*\\" + Goto error + ${EndIf} + + ${If} $0 =~ ".*\\" + ${Else} + Goto error + ${EndIf} + + ${If} "a" == "a" + ${AndIf} "a" =~ "[a-z]" + ${RESetOption} "CASELESS" + ${If} "a" == "b" + ${OrIf} "B" =~ "[a-z]" + ${Else} + Goto error + ${EndIf} + ${REClearOption} "CASELESS" + ${Else} + Goto error + ${EndIf} + + StrCpy $0 "" + ${IfThen} "a" !~ "[A-Z]" ${|} StrCpy $0 "1" ${|} + StrCmp $0 1 0 error + + StrCpy $0 "" + ${DoWhile} $0 !~ "000000" + StrCpy $0 "$00" + StrCmp $0 "0000000" error + ${Loop} + StrCmp $0 "000000" 0 error + + goto +2 + error: + SetErrors + + Pop $0 + + ${StackVerificationEnd} + +SectionEnd + +Section GetSetOptions + !define OptionTest `!insertmacro OptionTest` + !macro OptionTest OPTION + # Each option should be false to start with + # because we called REClearAllOptions + ${REGetOption} $OUT ${OPTION} + IfErrors error + StrCmp $OUT "false" 0 error + + # Set option and test + ${RESetOption} ${OPTION} + IfErrors error + ${REGetOption} $OUT ${OPTION} + IfErrors error + StrCmp $OUT "true" 0 error + + # Clear option and test + ${REClearOption} ${OPTION} + IfErrors error + ${REGetOption} $OUT ${OPTION} + IfErrors error + StrCmp $OUT "false" 0 error + !macroend + + ${StackVerificationStart} GetSetOptions + + ${REClearAllOptions} + IfErrors error + + ${OptionTest} "MULTILINE" + ${OptionTest} "CASELESS" + ${OptionTest} "DOTALL" + ${OptionTest} "EXTENDED" + ${OptionTest} "UTF8" + ${OptionTest} "DOLLAR_ENDONLY" + ${OptionTest} "EXTRA" + ${OptionTest} "UNGREEDY" + ${OptionTest} "NO_AUTO_CAPTURE" + ${OptionTest} "i" + ${OptionTest} "m" + ${OptionTest} "x" + ${OptionTest} "s" + + goto +2 + error: + SetErrors + + ${StackVerificationEnd} +SectionEnd + +Section QuoteMeta + !define QuoteMetaTest `!insertmacro QuoteMetaTest` + !macro QuoteMetaTest UNQUOTED QUOTED + ${REQuoteMeta} $OUT `${UNQUOTED}` + IfErrors error + StrCmp $OUT `${QUOTED}` 0 error + !macroend + + ${StackVerificationStart} QuoteMeta + + ${QuoteMetaTest} ".*" "\.\*" + ${QuoteMetaTest} "(.*" "\(\.\*" + + goto +2 + error: + SetErrors + + ${StackVerificationEnd} +SectionEnd + +Section CheckPattern + !define CheckPatternTest `!insertmacro CheckPatternTest` + !macro CheckPatternTest PATTERN BAD + ${RECheckPattern} $OUT `${PATTERN}` + IfErrors error + StrCpy $OUT $OUT 1 + StrLen $OUT $OUT + StrCmp $OUT `${BAD}` 0 error + !macroend + + ${StackVerificationStart} CheckPattern + + ${CheckPatternTest} ".*" 0 + ${CheckPatternTest} "(.*" 1 + + goto +2 + error: + SetErrors + + ${StackVerificationEnd} +SectionEnd + +Section Matches + !define MatchTest `!insertmacro MatchTest` + !macro MatchTest PATTERN SUBJECT PARTIAL RESULT +#DetailPrint "PATTERN=${PATTERN}, SUBJECT=${SUBJECT}" + ${REMatches} $OUT `${PATTERN}` `${SUBJECT}` `${PARTIAL}` + IfErrors error + StrCmp $OUT `${RESULT}` 0 error + !macroend + + ${StackVerificationStart} Matches + + # Check some basic patterns + ${REClearAllOptions} + ${MatchTest} ".*" "SUBJECT" 0 "true" + ${MatchTest} "S.*" "SUBJECT" 0 "true" + ${MatchTest} "s.*" "SUBJECT" 0 "false" + ${MatchTest} "S.*(ECT)+" "SUBJECT" 0 "true" + ${MatchTest} "S.*(ECT!)*" "SUBJECT" 0 "true" + ${MatchTest} "S.*(ECT){1}" "SUBJECT" 0 "true" + ${MatchTest} "S.*(ECT){2}" "SUBJECT" 0 "false" + ${MatchTest} "S.*(ECT){1,2}" "SUBJECT" 0 "true" + ${MatchTest} "SUBJ+(ECT){1}" "SUBJECT" 0 "true" + + # Check some more complicated patterns (backreferences) + ${MatchTest} "(e)l\g{1}phant" "elephant" 0 "true" + ${MatchTest} "(?123)[\d]*\k4567890" "12345678901234567890" 0 "true" + ${MatchTest} "(?123)[\d]*\k[\d]*" "12341235" 0 "true" + ${MatchTest} "(?123)[\d]*\k[\d]*" "12341245" 0 "false" + + # Check some more complicated patterns (lookaheads) + ${MatchTest} "Computer(?=way)" "Computerway" 0 "false" + ${MatchTest} "Computer(?=[a-z]+)" "Computer" 0 "false" + ${MatchTest} "Computer(?=[a-z]*)" "Computer" 0 "true" + ${MatchTest} "Computer(?![a-z]{4})w.*" "Computerway" 0 "true" + ${MatchTest} "Computer(?![a-z]{4})w.*" "Computerway Business Solutions" 0 "true" + ${MatchTest} "Computer(?![a-z]{4})w.*" "Computerwayz" 0 "false" + + # Check some more complicated patterns (lookbehinds) + ${MatchTest} ".*(?<=nsis[^1])\s+is\s+the\s+best!" "nsis2 is the$\nbest!" 0 "true" + ${MatchTest} ".*(?<=nsis[^1])\s+is\s+the\s+best!" "nsis1 is the best!" 0 "false" + + # Check partial matches + ${MatchTest} "U[\S+]J" "SUBJECT" 0 "false" + ${MatchTest} "U[\S+]J" "SUBJECT" 1 "true" + + # Try the options + ${RESetOption} "CASELESS" + ${MatchTest} "subject" "SUBJECT" 0 "true" + ${REClearOption} "CASELESS" + ${MatchTest} "subject" "SUBJECT" 0 "false" + + ${RESetOption} "DOTALL" + ${MatchTest} "SUB.JECT" "SUB$\nJECT" 0 "true" + ${REClearOption} "DOTALL" + ${MatchTest} "SUB.JECT" "SUB$\nJECT" 0 "false" + + ${RESetOption} "MULTILINE" + ${MatchTest} "^abc\s?$$.*" "abc$\r$\ndef" 0 "true" + ${REClearOption} "MULTILINE" + ${MatchTest} "^abc\s?$$.*" "abc$\r$\ndef" 0 "false" + + ${RESetOption} "DOLLAR_ENDONLY" + ${MatchTest} "SUBJECT$$" "SUBJECT$\n" 1 "false" + ${REClearOption} "DOLLAR_ENDONLY" + ${MatchTest} "SUBJECT$$" "SUBJECT$\n" 1 "true" + + ${RESetOption} "EXTENDED" + ${MatchTest} ".* CT" "SUBJECT" 0 "true" + ${MatchTest} ".*CT # Comment" "SUBJECT" 0 "true" + ${REClearOption} "EXTENDED" + ${MatchTest} ".* CT" "SUBJECT" 0 "false" + ${MatchTest} ".*CT # Comment" "SUBJECT" 0 "false" + + ${RESetOption} "UNGREEDY" + ${MatchTest} "/\*.*\*/" "/* a */ b /* c */" 0 "false" + ${MatchTest} "/\*.*?\*/" "/* a */ b /* c */" 0 "true" + ${REClearOption} "UNGREEDY" + ${MatchTest} "/\*.*\*/" "/* a */ b /* c */" 0 "true" + ${MatchTest} "/\*.*?\*/" "/* a */ b /* c */" 0 "false" + + # Try inline Perl options + ${MatchTest} "(?i)subject" "SUBJECT" 0 "true" + ${MatchTest} "(?-i)subject" "SUBJECT" 0 "false" + ${MatchTest} "SUB(?i)jec(?-i)t" "SUBJECT" 0 "false" + ${MatchTest} "SUB(?i)jec(?-i)t" "SUBJECt" 0 "true" + ${MatchTest} "(Line[1-2].?){2}" "Line 1$\nLine 2" 0 "false" + ${MatchTest} "(Line[1-2](?s).?){2}" "Line 1$\nLine 2" 0 "false" + + goto +2 + error: + SetErrors + + ${StackVerificationEnd} +SectionEnd + +Section CaptureMatches + !define CaptureMatchTest0 `!insertmacro CaptureMatchTest0` + !macro CaptureMatchTest0 PATTERN SUBJECT PARTIAL + ${RECaptureMatches} $OUT `${PATTERN}` `${SUBJECT}` `${PARTIAL}` + IfErrors error + StrCmp $OUT 0 0 error + !macroend + !define CaptureMatchTest1 `!insertmacro CaptureMatchTest1` + !macro CaptureMatchTest1 PATTERN SUBJECT PARTIAL RESULT + ${RECaptureMatches} $OUT `${PATTERN}` `${SUBJECT}` `${PARTIAL}` + IfErrors error + StrCmp $OUT 1 0 error + Pop $OUT + StrCmp $OUT `${RESULT}` 0 error + !macroend + !define CaptureMatchTest2 `!insertmacro CaptureMatchTest2` + !macro CaptureMatchTest2 PATTERN SUBJECT PARTIAL RESULT1 RESULT2 + ${RECaptureMatches} $OUT `${PATTERN}` `${SUBJECT}` `${PARTIAL}` + IfErrors error + StrCmp $OUT 2 0 error + Pop $OUT + StrCmp $OUT `${RESULT1}` 0 error + Pop $OUT + StrCmp $OUT `${RESULT2}` 0 error + !macroend + + ${StackVerificationStart} CaptureMatches + + ${CaptureMatchTest1} "(.*)" "SUBJECT" 0 "SUBJECT" + ${CaptureMatchTest1} "S(.*)" "SUBJECT" 0 "UBJECT" + ${CaptureMatchTest1} "S([TCEJBUS]*)" "SUBJECT" 0 "UBJECT" + + ${CaptureMatchTest2} "(S([TCEJBUS]*))" "SUBJECT" 0 "SUBJECT" "UBJECT" + ${CaptureMatchTest2} "(S(.*)T)" "SUBJECT" 0 "SUBJECT" "UBJEC" + ${CaptureMatchTest2} "(S(?:UBJ)ECT(.*))" "SUBJECT" 0 "SUBJECT" "" + + # Test NO_AUTO_CAPTURE option + ${RESetOption} "NO_AUTO_CAPTURE" + ${CaptureMatchTest0} "(.*)" "SUBJECT" 0 + ${REClearOption} "NO_AUTO_CAPTURE" + ${CaptureMatchTest1} "(.*)" "SUBJECT" 0 "SUBJECT" + + goto +2 + error: + SetErrors + + ${StackVerificationEnd} +SectionEnd + +Section Find + !define FindTest0 `!insertmacro FindTest0` + !macro FindTest0 PATTERN SUBJECT + ${REFind} $OUT `${PATTERN}` `${SUBJECT}` + IfErrors error + StrCmp $OUT 0 0 error + !macroend + !define FindTest1 `!insertmacro FindTest1` + !macro FindTest1 PATTERN SUBJECT RESULT + ${REFind} $OUT `${PATTERN}` `${SUBJECT}` + IfErrors error + StrCmp `${RESULT}` "false" +1 +2 + StrCmp $OUT "false" +4 error + StrCmp $OUT 1 0 error + Pop $OUT + StrCmp $OUT `${RESULT}` 0 error + !macroend + !define FindNextTest1 `!insertmacro FindNextTest1` + !macro FindNextTest1 RESULT + ${REFindNext} $OUT + IfErrors error + StrCmp `${RESULT}` "false" +1 +2 + StrCmp $OUT "false" +4 error + StrCmp $OUT 1 0 error + Pop $OUT + StrCmp $OUT `${RESULT}` 0 error + !macroend + !define FindTest2 `!insertmacro FindTest2` + !macro FindTest2 PATTERN SUBJECT RESULT1 RESULT2 + ${REFind} $OUT `${PATTERN}` `${SUBJECT}` + IfErrors error + StrCmp `${RESULT1}` "false" +1 +2 + StrCmp $OUT "false" +6 error + StrCmp $OUT 2 0 error + Pop $OUT + StrCmp $OUT `${RESULT1}` 0 error + Pop $OUT + StrCmp $OUT `${RESULT2}` 0 error + !macroend + !define FindNextTest2 `!insertmacro FindNextTest2` + !macro FindNextTest2 RESULT1 RESULT2 + ${REFindNext} $OUT + IfErrors error + StrCmp `${RESULT1}` "false" +1 +2 + StrCmp $OUT "false" +6 error + StrCmp $OUT 2 0 error + Pop $OUT + StrCmp $OUT `${RESULT1}` 0 error + Pop $OUT + StrCmp $OUT `${RESULT2}` 0 error + !macroend + + ${StackVerificationStart} Find + + ${FindTest1} "D" "ABCD" "D" + ${FindTest1} "E" "ABCD" "false" + ${FindTest2} "(D)..A..(D)" "DCBABCD" "D" "D" + ${FindTest1} "x" "ABCxDEFxGHI" "x" + ${FindNextTest1} "x" + ${FindNextTest1} "false" + ${FindTest2} "([^;=]+)=([^;=]*)" "name1=value1;name2=value2" "name1" "value1" + ${FindNextTest2} "name2" "value2" + ${FindNextTest2} "false" "" + + ${REFindClose} + IfErrors error + + goto +2 + error: + SetErrors + + ${StackVerificationEnd} +SectionEnd + +Section Replace + !define ReplaceTest `!insertmacro ReplaceTest` + !macro ReplaceTest PATTERN SUBJECT REPLACEMENT RESULT + ${REReplace} $OUT `${PATTERN}` `${SUBJECT}` `${REPLACEMENT}` 0 + IfErrors error + StrCmp $OUT `${RESULT}` 0 error + !macroend + !define ReplaceAllTest `!insertmacro ReplaceAllTest` + !macro ReplaceAllTest PATTERN SUBJECT REPLACEMENT RESULT + ${REReplace} $OUT `${PATTERN}` `${SUBJECT}` `${REPLACEMENT}` 1 + IfErrors error + StrCmp $OUT `${RESULT}` 0 error + !macroend + + ${StackVerificationStart} Replace + + # Try some simple replacements + ${ReplaceTest} "a" "Hallo World!" "e" "Hello World!" + ${ReplaceTest} "z" "zbczbc" "a" "abczbc" + ${ReplaceTest} "." "zbczbc" "x" "xbczbc" + ${ReplaceTest} ".{3}" "zbczbc" "x" "xzbc" + + ${ReplaceAllTest} "z" "zbczbc" "a" "abcabc" + ${ReplaceAllTest} "." "zbczbc" "x" "xxxxxx" + ${ReplaceAllTest} ".{3}" "zbczbc" "x" "xx" + + # Try some replacements with capturing + ${ReplaceTest} "h([\S]*)" "hello hello hello" "H\1" "Hello hello hello" + ${ReplaceAllTest} "h([\S]*)" "hello hello hello" "H\1" "Hello Hello Hello" + ${ReplaceAllTest} "(he)([\S]*)" "hello hello hello" "'a\2" "'allo 'allo 'allo" + ${ReplaceTest} "(he)([\S]*)" "hello hello hello" "'a\2" "'allo hello hello" + + goto +2 + error: + SetErrors + + ${StackVerificationEnd} +SectionEnd + +;############### UNINSTALL ############### + +Section un.Uninstall + # Just check that each function inserts correctly + ${un.REClearAllOptions} + ${un.REGetOption} $OUT "MULTILINE" + ${un.RESetOption} "MULTILINE" + ${un.REClearOption} "MULTILINE" + ${un.REMatches} $OUT "PATTERN" "SUBJECT" 1 + ${un.RECaptureMatches} $OUT "PATTERN" "SUBJECT" 1 + ${un.REReplace} $OUT "PATTERN" "SUBJECT" "REPLACEMENT" 1 + ${If} "c:\" un.!~ ".*\\" + ${EndIf} +SectionEnd \ No newline at end of file diff --git a/agent/installer/nsis_pcre/README b/agent/installer/nsis_pcre/README new file mode 100644 index 00000000000..fb7cba0ce33 --- /dev/null +++ b/agent/installer/nsis_pcre/README @@ -0,0 +1,3 @@ +This plugin was compiled using Microsoft Visual Studio .NET 2003. + +The pcre source code is available separately from http://www.pcre.org/. \ No newline at end of file diff --git a/agent/installer/nsis_pcre/exdll.c b/agent/installer/nsis_pcre/exdll.c new file mode 100644 index 00000000000..4d7480e8bce --- /dev/null +++ b/agent/installer/nsis_pcre/exdll.c @@ -0,0 +1,38 @@ +#include +#include "exdll.h" + +HINSTANCE g_hInstance; + +HWND g_hwndParent; + +void __declspec(dllexport) myFunction(HWND hwndParent, int string_size, + char *variables, stack_t **stacktop, + extra_parameters *extra) +{ + g_hwndParent=hwndParent; + + EXDLL_INIT(); + + + // note if you want parameters from the stack, pop them off in order. + // i.e. if you are called via exdll::myFunction file.dat poop.dat + // calling popstring() the first time would give you file.dat, + // and the second time would give you poop.dat. + // you should empty the stack of your parameters, and ONLY your + // parameters. + + // do your stuff here + { + char buf[1024]; + wsprintf(buf,"$0=%s\n",getuservariable(INST_0)); + MessageBox(g_hwndParent,buf,0,MB_OK); + } +} + + + +BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved) +{ + g_hInstance=hInst; + return TRUE; +} diff --git a/agent/installer/nsis_pcre/exdll.h b/agent/installer/nsis_pcre/exdll.h new file mode 100644 index 00000000000..482b8a18ea0 --- /dev/null +++ b/agent/installer/nsis_pcre/exdll.h @@ -0,0 +1,117 @@ +#ifndef _EXDLL_H_ +#define _EXDLL_H_ + +// only include this file from one place in your DLL. +// (it is all static, if you use it in two places it will fail) + +#define EXDLL_INIT() { \ + g_stringsize=string_size; \ + g_stacktop=stacktop; \ + g_variables=variables; } + +// For page showing plug-ins +#define WM_NOTIFY_OUTER_NEXT (WM_USER+0x8) +#define WM_NOTIFY_CUSTOM_READY (WM_USER+0xd) +#define NOTIFY_BYE_BYE 'x' + +typedef struct _stack_t { + struct _stack_t *next; + char text[1]; // this should be the length of string_size +} stack_t; + + +static unsigned int g_stringsize; +static stack_t **g_stacktop; +static char *g_variables; + +static int __stdcall popstring(char *str); // 0 on success, 1 on empty stack +static void __stdcall pushstring(const char *str); + +enum +{ +INST_0, // $0 +INST_1, // $1 +INST_2, // $2 +INST_3, // $3 +INST_4, // $4 +INST_5, // $5 +INST_6, // $6 +INST_7, // $7 +INST_8, // $8 +INST_9, // $9 +INST_R0, // $R0 +INST_R1, // $R1 +INST_R2, // $R2 +INST_R3, // $R3 +INST_R4, // $R4 +INST_R5, // $R5 +INST_R6, // $R6 +INST_R7, // $R7 +INST_R8, // $R8 +INST_R9, // $R9 +INST_CMDLINE, // $CMDLINE +INST_INSTDIR, // $INSTDIR +INST_OUTDIR, // $OUTDIR +INST_EXEDIR, // $EXEDIR +INST_LANG, // $LANGUAGE +__INST_LAST +}; + +typedef struct { + int autoclose; + int all_user_var; + int exec_error; + int abort; + int exec_reboot; + int reboot_called; + int XXX_cur_insttype; // deprecated + int XXX_insttype_changed; // deprecated + int silent; + int instdir_error; + int rtl; + int errlvl; +} exec_flags_type; + +typedef struct { + exec_flags_type *exec_flags; + int (__stdcall *ExecuteCodeSegment)(int, HWND); + void (__stdcall *validate_filename)(char *); +} extra_parameters; + +// utility functions (not required but often useful) +static int __stdcall popstring(char *str) +{ + stack_t *th; + if (!g_stacktop || !*g_stacktop) return 1; + th=(*g_stacktop); + lstrcpy(str,th->text); + *g_stacktop = th->next; + GlobalFree((HGLOBAL)th); + return 0; +} + +static void __stdcall pushstring(const char *str) +{ + stack_t *th; + if (!g_stacktop) return; + th=(stack_t*)GlobalAlloc(GPTR,sizeof(stack_t)+g_stringsize); + lstrcpyn(th->text,str,g_stringsize); + th->next=*g_stacktop; + *g_stacktop=th; +} + +static char * __stdcall getuservariable(const int varnum) +{ + if (varnum < 0 || varnum >= __INST_LAST) return NULL; + return g_variables+varnum*g_stringsize; +} + +static void __stdcall setuservariable(const int varnum, const char *var) +{ + if (var != NULL && varnum >= 0 && varnum < __INST_LAST) + lstrcpy(g_variables + varnum*g_stringsize, var); +} + + + +#endif//_EXDLL_H_ diff --git a/agent/installer/nsis_service_lib.nsi b/agent/installer/nsis_service_lib.nsi new file mode 100644 index 00000000000..130a461317a --- /dev/null +++ b/agent/installer/nsis_service_lib.nsi @@ -0,0 +1,419 @@ +; NSIS SERVICE LIBRARY - servicelib.nsh +; Version 1.8.1 - Jun 21th, 2013 +; Questions/Comments - dselkirk@hotmail.com +; +; Description: +; Provides an interface to window services +; +; Inputs: +; action - systemlib action ie. create, delete, start, stop, pause, +; continue, installed, running, status +; name - name of service to manipulate +; param - action parameters; usage: var1=value1;var2=value2;...etc. +; (don't forget to add a ';' after the last value!) +; +; Actions: +; create - creates a new windows service +; Parameters: +; path - path to service executable +; autostart - automatically start with system ie. 1|0 +; interact - interact with the desktop ie. 1|0 +; depend - service dependencies +; user - user that runs the service +; password - password of the above user +; display - display name in service's console +; description - Description of service +; starttype - start type (supersedes autostart) +; servicetype - service type (supersedes interact) +; +; delete - deletes a windows service +; start - start a stopped windows service +; stop - stops a running windows service +; pause - pauses a running windows service +; continue - continues a paused windows service +; installed - is the provided service installed +; Parameters: +; action - if true then invokes the specified action +; running - is the provided service running +; Parameters: +; action - if true then invokes the specified action +; status - check the status of the provided service +; +; Usage: +; Method 1: +; Push "action" +; Push "name" +; Push "param" +; Call Service +; Pop $0 ;response +; +; Method 2: +; !insertmacro SERVICE "action" "name" "param" +; +; History: +; 1.0 - 09/15/2003 - Initial release +; 1.1 - 09/16/2003 - Changed &l to i, thx brainsucker +; 1.2 - 02/29/2004 - Fixed documentation. +; 1.3 - 01/05/2006 - Fixed interactive flag and pop order (Kichik) +; 1.4 - 12/07/2006 - Added display and depend, fixed datatypes (Vitoco) +; 1.5 - 06/25/2008 - Added description of service.(DeSafe.com/liuqixing#gmail.com) +; 1.5.1 - 06/12/2009 - Added use of __UNINSTALL__ +; 1.6 - 08/02/2010 - Fixed description implementation (Anders) +; 1.7 - 04/11/2010 - Added get running service process id (Nico) +; 1.8 - 24/03/2011 - Added starttype and servicetype (Sergius) +; 1.8.1 - 21/06/2013 - Added dynamic ASCII & Unicode support (Zinthose) + +!ifndef SERVICELIB + !define SERVICELIB + + !define SC_MANAGER_ALL_ACCESS 0x3F + !define SC_STATUS_PROCESS_INFO 0x0 + !define SERVICE_ALL_ACCESS 0xF01FF + + !define SERVICE_CONTROL_STOP 1 + !define SERVICE_CONTROL_PAUSE 2 + !define SERVICE_CONTROL_CONTINUE 3 + + !define SERVICE_STOPPED 0x1 + !define SERVICE_START_PENDING 0x2 + !define SERVICE_STOP_PENDING 0x3 + !define SERVICE_RUNNING 0x4 + !define SERVICE_CONTINUE_PENDING 0x5 + !define SERVICE_PAUSE_PENDING 0x6 + !define SERVICE_PAUSED 0x7 + + !define SERVICE_KERNEL_DRIVER 0x00000001 + !define SERVICE_FILE_SYSTEM_DRIVER 0x00000002 + !define SERVICE_WIN32_OWN_PROCESS 0x00000010 + !define SERVICE_WIN32_SHARE_PROCESS 0x00000020 + !define SERVICE_INTERACTIVE_PROCESS 0x00000100 + + + !define SERVICE_BOOT_START 0x00000000 + !define SERVICE_SYSTEM_START 0x00000001 + !define SERVICE_AUTO_START 0x00000002 + !define SERVICE_DEMAND_START 0x00000003 + !define SERVICE_DISABLED 0x00000004 + + ## Added by Zinthose for Native Unicode Support + !ifdef NSIS_UNICODE + !define APITAG "W" + !else + !define APITAG "A" + !endif + + !macro SERVICE ACTION NAME PARAM + Push '${ACTION}' + Push '${NAME}' + Push '${PARAM}' + !ifdef __UNINSTALL__ + Call un.Service + !else + Call Service + !endif + !macroend + + !macro FUNC_GETPARAM + Push $0 + Push $1 + Push $2 + Push $3 + Push $4 + Push $5 + Push $6 + Push $7 + Exch 8 + Pop $1 ;name + Exch 8 + Pop $2 ;source + StrCpy $0 "" + StrLen $7 $2 + StrCpy $3 0 + lbl_loop: + IntCmp $3 $7 0 0 lbl_done + StrLen $4 "$1=" + StrCpy $5 $2 $4 $3 + StrCmp $5 "$1=" 0 lbl_next + IntOp $5 $3 + $4 + StrCpy $3 $5 + lbl_loop2: + IntCmp $3 $7 0 0 lbl_done + StrCpy $6 $2 1 $3 + StrCmp $6 ";" 0 lbl_next2 + IntOp $6 $3 - $5 + StrCpy $0 $2 $6 $5 + Goto lbl_done + lbl_next2: + IntOp $3 $3 + 1 + Goto lbl_loop2 + lbl_next: + IntOp $3 $3 + 1 + Goto lbl_loop + lbl_done: + Pop $5 + Pop $4 + Pop $3 + Pop $2 + Pop $1 + Exch 2 + Pop $6 + Pop $7 + Exch $0 + !macroend + + !macro CALL_GETPARAM VAR NAME DEFAULT LABEL + Push $1 + Push ${NAME} + Call ${UN}GETPARAM + Pop $6 + StrCpy ${VAR} "${DEFAULT}" + StrCmp $6 "" "${LABEL}" 0 + StrCpy ${VAR} $6 + !macroend + + !macro FUNC_SERVICE UN + Push $0 + Push $1 + Push $2 + Push $3 + Push $4 + Push $5 + Push $6 + Push $7 + Exch 8 + Pop $1 ;param + Exch 8 + Pop $2 ;name + Exch 8 + Pop $3 ;action + ;$0 return + ;$4 OpenSCManager + ;$5 OpenService + + StrCpy $0 "false" + System::Call 'advapi32::OpenSCManager${APITAG}(n, n, i ${SC_MANAGER_ALL_ACCESS}) i.r4' + IntCmp $4 0 lbl_done + StrCmp $3 "create" lbl_create + System::Call 'advapi32::OpenService${APITAG}(i r4, t r2, i ${SERVICE_ALL_ACCESS}) i.r5' + IntCmp $5 0 lbl_done + + lbl_select: + StrCmp $3 "delete" lbl_delete + StrCmp $3 "start" lbl_start + StrCmp $3 "stop" lbl_stop + StrCmp $3 "pause" lbl_pause + StrCmp $3 "continue" lbl_continue + StrCmp $3 "installed" lbl_installed + StrCmp $3 "running" lbl_running + StrCmp $3 "status" lbl_status + StrCmp $3 "processid" lbl_processid + Goto lbl_done + + ; create service + lbl_create: + Push $R1 ;depend + Push $R2 ;user + Push $R3 ;password + Push $R4 ;servicetype/interact + Push $R5 ;starttype/autostart + Push $R6 ;path + Push $R7 ;display + Push $R8 ;description + + !insertmacro CALL_GETPARAM $R1 "depend" "n" "lbl_depend" + StrCpy $R1 't "$R1"' + lbl_depend: + StrCmp $R1 "n" 0 lbl_machine ;old name of depend param + !insertmacro CALL_GETPARAM $R1 "machine" "n" "lbl_machine" + StrCpy $R1 't "$R1"' + lbl_machine: + + !insertmacro CALL_GETPARAM $R2 "user" "n" "lbl_user" + StrCpy $R2 't "$R2"' + lbl_user: + + !insertmacro CALL_GETPARAM $R3 "password" "n" "lbl_password" + StrCpy $R3 't "$R3"' + lbl_password: + + !insertmacro CALL_GETPARAM $R4 "interact" "${SERVICE_WIN32_OWN_PROCESS}" "lbl_interact" + StrCpy $6 ${SERVICE_WIN32_OWN_PROCESS} + IntCmp $R4 0 +2 + IntOp $6 $6 | ${SERVICE_INTERACTIVE_PROCESS} + StrCpy $R4 $6 + lbl_interact: + + !insertmacro CALL_GETPARAM $R4 "servicetype" "$R4" "lbl_servicetype" + lbl_servicetype: + + !insertmacro CALL_GETPARAM $R5 "autostart" "${SERVICE_DEMAND_START}" "lbl_autostart" + StrCpy $6 ${SERVICE_DEMAND_START} + IntCmp $R5 0 +2 + StrCpy $6 ${SERVICE_AUTO_START} + StrCpy $R5 $6 + lbl_autostart: + + !insertmacro CALL_GETPARAM $R5 "starttype" "$R5" "lbl_starttype" + lbl_starttype: + + !insertmacro CALL_GETPARAM $R6 "path" "n" "lbl_path" + lbl_path: + + !insertmacro CALL_GETPARAM $R7 "display" "$2" "lbl_display" + lbl_display: + + !insertmacro CALL_GETPARAM $R8 "description" "$2" "lbl_description" + lbl_description: + + System::Call 'advapi32::CreateService${APITAG}(i r4, t r2, t R7, i ${SERVICE_ALL_ACCESS}, \ + i R4, i R5, i 0, t R6, n, n, $R1, $R2, $R3) i.r6' + + ; write description of service (SERVICE_CONFIG_DESCRIPTION) + System::Call 'advapi32::ChangeServiceConfig2${APITAG}(ir6,i1,*t "$R8")i.R7' + strcmp $R7 "error" 0 lbl_descriptioncomplete + WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\$2" "Description" $R8 + lbl_descriptioncomplete: + + Pop $R8 + Pop $R7 + Pop $R6 + Pop $R5 + Pop $R4 + Pop $R3 + Pop $R2 + Pop $R1 + StrCmp $6 0 lbl_done lbl_good + + ; delete service + lbl_delete: + System::Call 'advapi32::DeleteService(i r5) i.r6' + StrCmp $6 0 lbl_done lbl_good + + ; start service + lbl_start: + System::Call 'advapi32::StartService${APITAG}(i r5, i 0, i 0) i.r6' + StrCmp $6 0 lbl_done lbl_good + + ; stop service + lbl_stop: + Push $R1 + System::Call '*(i,i,i,i,i,i,i) i.R1' + System::Call 'advapi32::ControlService(i r5, i ${SERVICE_CONTROL_STOP}, i $R1) i' + System::Free $R1 + Pop $R1 + StrCmp $6 0 lbl_done lbl_good + + ; pause service + lbl_pause: + Push $R1 + System::Call '*(i,i,i,i,i,i,i) i.R1' + System::Call 'advapi32::ControlService(i r5, i ${SERVICE_CONTROL_PAUSE}, i $R1) i' + System::Free $R1 + Pop $R1 + StrCmp $6 0 lbl_done lbl_good + + ; continue service + lbl_continue: + Push $R1 + System::Call '*(i,i,i,i,i,i,i) i.R1' + System::Call 'advapi32::ControlService(i r5, i ${SERVICE_CONTROL_CONTINUE}, i $R1) i' + System::Free $R1 + Pop $R1 + StrCmp $6 0 lbl_done lbl_good + + ; is installed + lbl_installed: + !insertmacro CALL_GETPARAM $7 "action" "" "lbl_good" + StrCpy $3 $7 + Goto lbl_select + + ; is service running + lbl_running: + Push $R1 + System::Call '*(i,i,i,i,i,i,i) i.R1' + System::Call 'advapi32::QueryServiceStatus(i r5, i $R1) i' + System::Call '*$R1(i, i.r6)' + System::Free $R1 + Pop $R1 + IntFmt $6 "0x%X" $6 + StrCmp $6 ${SERVICE_RUNNING} 0 lbl_done + !insertmacro CALL_GETPARAM $7 "action" "" "lbl_good" + StrCpy $3 $7 + Goto lbl_select + + lbl_status: + Push $R1 + System::Call '*(i,i,i,i,i,i,i) i.R1' + System::Call 'advapi32::QueryServiceStatus(i r5, i $R1) i' + System::Call '*$R1(i, i .r6)' + System::Free $R1 + Pop $R1 + IntFmt $6 "0x%X" $6 + StrCpy $0 "running" + IntCmp $6 ${SERVICE_RUNNING} lbl_done + StrCpy $0 "stopped" + IntCmp $6 ${SERVICE_STOPPED} lbl_done + StrCpy $0 "start_pending" + IntCmp $6 ${SERVICE_START_PENDING} lbl_done + StrCpy $0 "stop_pending" + IntCmp $6 ${SERVICE_STOP_PENDING} lbl_done + StrCpy $0 "running" + IntCmp $6 ${SERVICE_RUNNING} lbl_done + StrCpy $0 "continue_pending" + IntCmp $6 ${SERVICE_CONTINUE_PENDING} lbl_done + StrCpy $0 "pause_pending" + IntCmp $6 ${SERVICE_PAUSE_PENDING} lbl_done + StrCpy $0 "paused" + IntCmp $6 ${SERVICE_PAUSED} lbl_done + StrCpy $0 "unknown" + Goto lbl_done + + lbl_processid: + Push $R1 + Push $R2 + System::Call '*(i,i,i,i,i,i,i,i,i) i.R1' + System::Call '*(i 0) i.R2' + System::Call "advapi32::QueryServiceStatusEx(i r5, i ${SC_STATUS_PROCESS_INFO}, i $R1, i 36, i $R2) i" + System::Call "*$R1(i,i,i,i,i,i,i, i .r0)" + System::Free $R2 + System::Free $R1 + Pop $R2 + Pop $R1 + Goto lbl_done + + lbl_good: + StrCpy $0 "true" + lbl_done: + IntCmp $5 0 +2 + System::Call 'advapi32::CloseServiceHandle(i r5) n' + IntCmp $4 0 +2 + System::Call 'advapi32::CloseServiceHandle(i r4) n' + Pop $4 + Pop $3 + Pop $2 + Pop $1 + Exch 3 + Pop $5 + Pop $7 + Pop $6 + Exch $0 + !macroend + + Function Service + !insertmacro FUNC_SERVICE "" + FunctionEnd + + Function un.Service + !insertmacro FUNC_SERVICE "un." + FunctionEnd + + Function GetParam + !insertmacro FUNC_GETPARAM + FunctionEnd + + Function un.GetParam + !insertmacro FUNC_GETPARAM + FunctionEnd + + !undef APITAG +!endif diff --git a/agent/installer/resources/encryption_dlg.nsddef b/agent/installer/resources/encryption_dlg.nsddef new file mode 100644 index 00000000000..c4a55c45b4e --- /dev/null +++ b/agent/installer/resources/encryption_dlg.nsddef @@ -0,0 +1,25 @@ + + + + Call init_encryption_dlg +Call on_encryptioncheckbox_click + + + + + + + + + \ No newline at end of file diff --git a/agent/installer/resources/encryption_dlg.nsdinc b/agent/installer/resources/encryption_dlg.nsdinc new file mode 100644 index 00000000000..6a56fbe5191 --- /dev/null +++ b/agent/installer/resources/encryption_dlg.nsdinc @@ -0,0 +1,179 @@ +; ========================================================= +; This file was generated by NSISDialogDesigner 1.6.0.0 +; https://coolsoft.altervista.org/nsisdialogdesigner +; +; Do not edit it manually, use NSISDialogDesigner instead! +; ========================================================= + +; handle variables +Var hCtl_encryption +Var hCtl_encryption_EncryptionCheckBox +Var hCtl_encryption_EncryptionGroupBox +Var hCtl_encryption_ca_name_help +Var hCtl_encryption_ca_name_help_hImage +Var hCtl_encryption_ca_file_help +Var hCtl_encryption_ca_file_help_hImage +Var hCtl_encryption_certificate_file_help +Var hCtl_encryption_certificate_file_help_hImage +Var hCtl_encryption_private_key_file_help +Var hCtl_encryption_private_key_file_help_hImage +Var hCtl_encryption_ca_name +Var hCtl_encryption_label_ca_name +Var hCtl_encryption_ca_file_Txt +Var hCtl_encryption_ca_file_Btn +Var hCtl_encryption_certificate_file_Txt +Var hCtl_encryption_certificate_file_Btn +Var hCtl_encryption_label_ca_file +Var hCtl_encryption_private_key_file_Txt +Var hCtl_encryption_private_key_file_Btn +Var hCtl_encryption_label_certificate_file +Var hCtl_encryption_label_private_key_file + + +; dialog create function +Function fnc_encryption_Create + + ; === encryption (type: Dialog) === + nsDialogs::Create 1018 + Pop $hCtl_encryption + ${If} $hCtl_encryption == error + Abort + ${EndIf} + !insertmacro MUI_HEADER_TEXT "Centreon Monitoring Agent" "Encryption parameters" + + ; === EncryptionCheckBox (type: Checkbox) === + ${NSD_CreateCheckbox} 8u 2u 68u 15u "Encryption" + Pop $hCtl_encryption_EncryptionCheckBox + ${NSD_OnClick} $hCtl_encryption_EncryptionCheckBox on_encryptioncheckbox_click + + ; === EncryptionGroupBox (type: GroupBox) === + ${NSD_CreateGroupBox} 8u 20u 255u 84u "Certificates" + Pop $hCtl_encryption_EncryptionGroupBox + + ; === ca_name_help (type: Bitmap) === + ${NSD_CreateBitmap} 246u 85u 12u 11u "" + Pop $hCtl_encryption_ca_name_help + ${NSD_OnClick} $hCtl_encryption_ca_name_help ca_name_help_onClick + File "/oname=$PLUGINSDIR\info.bmp" "resources\info.bmp" + ${NSD_SetImage} $hCtl_encryption_ca_name_help "$PLUGINSDIR\info.bmp" $hCtl_encryption_ca_name_help_hImage + + ; === ca_file_help (type: Bitmap) === + ${NSD_CreateBitmap} 246u 66u 12u 11u "" + Pop $hCtl_encryption_ca_file_help + ${NSD_OnClick} $hCtl_encryption_ca_file_help ca_file_help_onClick + File "/oname=$PLUGINSDIR\info.bmp" "resources\info.bmp" + ${NSD_SetImage} $hCtl_encryption_ca_file_help "$PLUGINSDIR\info.bmp" $hCtl_encryption_ca_file_help_hImage + + ; === certificate_file_help (type: Bitmap) === + ${NSD_CreateBitmap} 246u 47u 12u 11u "" + Pop $hCtl_encryption_certificate_file_help + ${NSD_OnClick} $hCtl_encryption_certificate_file_help certificate_file_help_onClick + File "/oname=$PLUGINSDIR\info.bmp" "resources\info.bmp" + ${NSD_SetImage} $hCtl_encryption_certificate_file_help "$PLUGINSDIR\info.bmp" $hCtl_encryption_certificate_file_help_hImage + + ; === private_key_file_help (type: Bitmap) === + ${NSD_CreateBitmap} 246u 29u 12u 11u "" + Pop $hCtl_encryption_private_key_file_help + ${NSD_OnClick} $hCtl_encryption_private_key_file_help private_key_file_help_onClick + File "/oname=$PLUGINSDIR\info.bmp" "resources\info.bmp" + ${NSD_SetImage} $hCtl_encryption_private_key_file_help "$PLUGINSDIR\info.bmp" $hCtl_encryption_private_key_file_help_hImage + + ; === ca_name (type: Text) === + ${NSD_CreateText} 115u 84u 127u 12u "" + Pop $hCtl_encryption_ca_name + + ; === label_ca_name (type: Label) === + ${NSD_CreateLabel} 12u 86u 92u 10u "Certificate Common Name" + Pop $hCtl_encryption_label_ca_name + + ; === ca_file_Txt (type: Text) === + ${NSD_CreateText} 115u 65u 106u 12u "" + Pop $hCtl_encryption_ca_file_Txt + + ; === ca_file_Btn (type: Button) === + ${NSD_CreateButton} 222u 65u 20u 12u "..." + Pop $hCtl_encryption_ca_file_Btn + ${NSD_OnClick} $hCtl_encryption_ca_file_Btn fnc_hCtl_encryption_ca_file_Click + + ; === certificate_file_Txt (type: Text) === + ${NSD_CreateText} 115u 46u 106u 12u "" + Pop $hCtl_encryption_certificate_file_Txt + + ; === certificate_file_Btn (type: Button) === + ${NSD_CreateButton} 222u 46u 20u 12u "..." + Pop $hCtl_encryption_certificate_file_Btn + ${NSD_OnClick} $hCtl_encryption_certificate_file_Btn fnc_hCtl_encryption_certificate_file_Click + + ; === label_ca_file (type: Label) === + ${NSD_CreateLabel} 12u 67u 99u 10u "Trusted CA's certificate file:" + Pop $hCtl_encryption_label_ca_file + + ; === private_key_file_Txt (type: Text) === + ${NSD_CreateText} 115u 28u 106u 12u "" + Pop $hCtl_encryption_private_key_file_Txt + + ; === private_key_file_Btn (type: Button) === + ${NSD_CreateButton} 222u 28u 20u 12u "..." + Pop $hCtl_encryption_private_key_file_Btn + ${NSD_OnClick} $hCtl_encryption_private_key_file_Btn fnc_hCtl_encryption_private_key_file_Click + + ; === label_certificate_file (type: Label) === + ${NSD_CreateLabel} 12u 49u 66u 10u "Certificate file:" + Pop $hCtl_encryption_label_certificate_file + + ; === label_private_key_file (type: Label) === + ${NSD_CreateLabel} 12u 30u 66u 10u "Private key file:" + Pop $hCtl_encryption_label_private_key_file + + ; CreateFunctionCustomScript + Call init_encryption_dlg + Call on_encryptioncheckbox_click + + +FunctionEnd + +; dialog show function +Function fnc_encryption_Show + Call fnc_encryption_Create + nsDialogs::Show +FunctionEnd + + +; onClick handler for FileRequest Button $hCtl_encryption_ca_file_Btn +Function fnc_hCtl_encryption_ca_file_Click + Pop $R0 + ${If} $R0 == $hCtl_encryption_ca_file_Btn + ${NSD_GetText} $hCtl_encryption_ca_file_Txt $R0 + nsDialogs::SelectFileDialog open "$R0" "*.crt files|*.crt" + Pop $R0 + ${If} "$R0" != "" + ${NSD_SetText} $hCtl_encryption_ca_file_Txt "$R0" + ${EndIf} + ${EndIf} +FunctionEnd + +; onClick handler for FileRequest Button $hCtl_encryption_certificate_file_Btn +Function fnc_hCtl_encryption_certificate_file_Click + Pop $R0 + ${If} $R0 == $hCtl_encryption_certificate_file_Btn + ${NSD_GetText} $hCtl_encryption_certificate_file_Txt $R0 + nsDialogs::SelectFileDialog open "$R0" "*.key files|*.key" + Pop $R0 + ${If} "$R0" != "" + ${NSD_SetText} $hCtl_encryption_certificate_file_Txt "$R0" + ${EndIf} + ${EndIf} +FunctionEnd + +; onClick handler for FileRequest Button $hCtl_encryption_private_key_file_Btn +Function fnc_hCtl_encryption_private_key_file_Click + Pop $R0 + ${If} $R0 == $hCtl_encryption_private_key_file_Btn + ${NSD_GetText} $hCtl_encryption_private_key_file_Txt $R0 + nsDialogs::SelectFileDialog open "$R0" "*.crt files|*.crt" + Pop $R0 + ${If} "$R0" != "" + ${NSD_SetText} $hCtl_encryption_private_key_file_Txt "$R0" + ${EndIf} + ${EndIf} +FunctionEnd diff --git a/agent/installer/resources/info.bmp b/agent/installer/resources/info.bmp new file mode 100644 index 00000000000..6cc06dbea25 Binary files /dev/null and b/agent/installer/resources/info.bmp differ diff --git a/agent/installer/resources/license.txt b/agent/installer/resources/license.txt new file mode 100644 index 00000000000..84e6db45bf2 --- /dev/null +++ b/agent/installer/resources/license.txt @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/agent/installer/resources/log_dlg.nsddef b/agent/installer/resources/log_dlg.nsddef new file mode 100644 index 00000000000..e6d112a1f12 --- /dev/null +++ b/agent/installer/resources/log_dlg.nsddef @@ -0,0 +1,39 @@ + + + + Call init_log_dlg +Call on_log_type_changed + + + + + + + event-log + file + + + + + Off + Critical + Error + Warning + Info + Debug + Trace + + + \ No newline at end of file diff --git a/agent/installer/resources/log_dlg.nsdinc b/agent/installer/resources/log_dlg.nsdinc new file mode 100644 index 00000000000..9d67db14bd7 --- /dev/null +++ b/agent/installer/resources/log_dlg.nsdinc @@ -0,0 +1,137 @@ +; ========================================================= +; This file was generated by NSISDialogDesigner 1.6.0.0 +; https://coolsoft.altervista.org/nsisdialogdesigner +; +; Do not edit it manually, use NSISDialogDesigner instead! +; ========================================================= + +; handle variables +Var hCtl_log_dlg +Var hCtl_log_dlg_file_group +Var hCtl_log_dlg_max_files_help +Var hCtl_log_dlg_max_files_help_hImage +Var hCtl_log_dlg_max_file_size_help +Var hCtl_log_dlg_max_file_size_help_hImage +Var hCtl_log_dlg_label_max_files +Var hCtl_log_dlg_log_file_Txt +Var hCtl_log_dlg_log_file_Btn +Var hCtl_log_dlg_label_max_file_size +Var hCtl_log_dlg_max_file_size +Var hCtl_log_dlg_label_log_file +Var hCtl_log_dlg_max_files +Var hCtl_log_dlg_log_type +Var hCtl_log_dlg_log_level +Var hCtl_log_dlg_Label12 +Var hCtl_log_dlg_Label13 + + +; dialog create function +Function fnc_log_dlg_Create + + ; === log_dlg (type: Dialog) === + nsDialogs::Create 1018 + Pop $hCtl_log_dlg + ${If} $hCtl_log_dlg == error + Abort + ${EndIf} + !insertmacro MUI_HEADER_TEXT "logs" "logs" + + ; === file_group (type: GroupBox) === + ${NSD_CreateGroupBox} 8u 35u 255u 63u "Log File" + Pop $hCtl_log_dlg_file_group + + ; === max_files_help (type: Bitmap) === + ${NSD_CreateBitmap} 186u 76u 12u 11u "" + Pop $hCtl_log_dlg_max_files_help + ${NSD_OnClick} $hCtl_log_dlg_max_files_help max_files_help_onClick + File "/oname=$PLUGINSDIR\info.bmp" "resources\info.bmp" + ${NSD_SetImage} $hCtl_log_dlg_max_files_help "$PLUGINSDIR\info.bmp" $hCtl_log_dlg_max_files_help_hImage + + ; === max_file_size_help (type: Bitmap) === + ${NSD_CreateBitmap} 186u 61u 12u 11u "" + Pop $hCtl_log_dlg_max_file_size_help + ${NSD_OnClick} $hCtl_log_dlg_max_file_size_help max_file_size_help_onClick + File "/oname=$PLUGINSDIR\info.bmp" "resources\info.bmp" + ${NSD_SetImage} $hCtl_log_dlg_max_file_size_help "$PLUGINSDIR\info.bmp" $hCtl_log_dlg_max_file_size_help_hImage + + ; === label_max_files (type: Label) === + ${NSD_CreateLabel} 13u 78u 73u 10u "Max number of files:" + Pop $hCtl_log_dlg_label_max_files + + ; === log_file_Txt (type: Text) === + ${NSD_CreateText} 88u 44u 150u 12u "" + Pop $hCtl_log_dlg_log_file_Txt + + ; === log_file_Btn (type: Button) === + ${NSD_CreateButton} 240u 44u 20u 12u "..." + Pop $hCtl_log_dlg_log_file_Btn + ${NSD_OnClick} $hCtl_log_dlg_log_file_Btn fnc_hCtl_log_dlg_log_file_Click + + ; === label_max_file_size (type: Label) === + ${NSD_CreateLabel} 13u 61u 73u 11u "Max File Size (Mo):" + Pop $hCtl_log_dlg_label_max_file_size + + ; === max_file_size (type: Number) === + ${NSD_CreateNumber} 88u 60u 93u 12u "" + Pop $hCtl_log_dlg_max_file_size + + ; === label_log_file (type: Label) === + ${NSD_CreateLabel} 13u 46u 66u 10u "Log file:" + Pop $hCtl_log_dlg_label_log_file + + ; === max_files (type: Number) === + ${NSD_CreateNumber} 88u 76u 93u 12u "" + Pop $hCtl_log_dlg_max_files + + ; === log_type (type: DropList) === + ${NSD_CreateDropList} 111u 2u 80u 13u "" + Pop $hCtl_log_dlg_log_type + ${NSD_OnChange} $hCtl_log_dlg_log_type on_log_type_changed + ${NSD_CB_AddString} $hCtl_log_dlg_log_type "Event-log" + ${NSD_CB_AddString} $hCtl_log_dlg_log_type "File" + + ; === log_level (type: DropList) === + ${NSD_CreateDropList} 111u 18u 80u 13u "" + Pop $hCtl_log_dlg_log_level + ${NSD_CB_AddString} $hCtl_log_dlg_log_level "Off" + ${NSD_CB_AddString} $hCtl_log_dlg_log_level "Critical" + ${NSD_CB_AddString} $hCtl_log_dlg_log_level "Error" + ${NSD_CB_AddString} $hCtl_log_dlg_log_level "Warning" + ${NSD_CB_AddString} $hCtl_log_dlg_log_level "Info" + ${NSD_CB_AddString} $hCtl_log_dlg_log_level "Debug" + ${NSD_CB_AddString} $hCtl_log_dlg_log_level "Trace" + + ; === Label12 (type: Label) === + ${NSD_CreateLabel} 8u 20u 57u 11u "Log level:" + Pop $hCtl_log_dlg_Label12 + + ; === Label13 (type: Label) === + ${NSD_CreateLabel} 8u 4u 57u 11u "Log type:" + Pop $hCtl_log_dlg_Label13 + + ; CreateFunctionCustomScript + Call init_log_dlg + Call on_log_type_changed + + +FunctionEnd + +; dialog show function +Function fnc_log_dlg_Show + Call fnc_log_dlg_Create + nsDialogs::Show +FunctionEnd + + +; onClick handler for FileRequest Button $hCtl_log_dlg_log_file_Btn +Function fnc_hCtl_log_dlg_log_file_Click + Pop $R0 + ${If} $R0 == $hCtl_log_dlg_log_file_Btn + ${NSD_GetText} $hCtl_log_dlg_log_file_Txt $R0 + nsDialogs::SelectFileDialog save "$R0" ".log files|*.log" + Pop $R0 + ${If} "$R0" != "" + ${NSD_SetText} $hCtl_log_dlg_log_file_Txt "$R0" + ${EndIf} + ${EndIf} +FunctionEnd diff --git a/agent/installer/resources/logo_centreon.ico b/agent/installer/resources/logo_centreon.ico new file mode 100644 index 00000000000..8e032cde7c8 Binary files /dev/null and b/agent/installer/resources/logo_centreon.ico differ diff --git a/agent/installer/resources/setup_dlg.nsddef b/agent/installer/resources/setup_dlg.nsddef new file mode 100644 index 00000000000..263c0872502 --- /dev/null +++ b/agent/installer/resources/setup_dlg.nsddef @@ -0,0 +1,17 @@ + + + + Call init_setup_dlg + + + + \ No newline at end of file diff --git a/agent/installer/resources/setup_dlg.nsdinc b/agent/installer/resources/setup_dlg.nsdinc new file mode 100644 index 00000000000..7d10474d655 --- /dev/null +++ b/agent/installer/resources/setup_dlg.nsdinc @@ -0,0 +1,86 @@ +; ========================================================= +; This file was generated by NSISDialogDesigner 1.6.0.0 +; https://coolsoft.altervista.org/nsisdialogdesigner +; +; Do not edit it manually, use NSISDialogDesigner instead! +; ========================================================= + +; handle variables +Var hCtl_cma +Var hCtl_cma_reverse_help +Var hCtl_cma_reverse_help_hImage +Var hCtl_cma_endpoint_help +Var hCtl_cma_endpoint_help_hImage +Var hCtl_cma_hostname_help +Var hCtl_cma_hostname_help_hImage +Var hCtl_cma_endpoint_label +Var hCtl_cma_host_name +Var hCtl_cma_endpoint +Var hCtl_cma_reverse +Var hCtl_cma_Label15 + + +; dialog create function +Function fnc_cma_Create + + ; === cma (type: Dialog) === + nsDialogs::Create 1018 + Pop $hCtl_cma + ${If} $hCtl_cma == error + Abort + ${EndIf} + !insertmacro MUI_HEADER_TEXT "Centreon Monitoring Agent" "Agent Configuration" + + ; === reverse_help (type: Bitmap) === + ${NSD_CreateBitmap} 105u 45u 12u 11u "" + Pop $hCtl_cma_reverse_help + ${NSD_OnClick} $hCtl_cma_reverse_help reverse_help_onClick + File "/oname=$PLUGINSDIR\info.bmp" "resources\info.bmp" + ${NSD_SetImage} $hCtl_cma_reverse_help "$PLUGINSDIR\info.bmp" $hCtl_cma_reverse_help_hImage + + ; === endpoint_help (type: Bitmap) === + ${NSD_CreateBitmap} 213u 19u 12u 11u "" + Pop $hCtl_cma_endpoint_help + ${NSD_OnClick} $hCtl_cma_endpoint_help endpoint_help_onClick + File "/oname=$PLUGINSDIR\info.bmp" "resources\info.bmp" + ${NSD_SetImage} $hCtl_cma_endpoint_help "$PLUGINSDIR\info.bmp" $hCtl_cma_endpoint_help_hImage + + ; === hostname_help (type: Bitmap) === + ${NSD_CreateBitmap} 213u 2u 12u 11u "" + Pop $hCtl_cma_hostname_help + ${NSD_OnClick} $hCtl_cma_hostname_help hostname_help_onClick + File "/oname=$PLUGINSDIR\info.bmp" "resources\info.bmp" + ${NSD_SetImage} $hCtl_cma_hostname_help "$PLUGINSDIR\info.bmp" $hCtl_cma_hostname_help_hImage + + ; === endpoint_label (type: Label) === + ${NSD_CreateLabel} 8u 20u 65u 10u "Poller endpoint:" + Pop $hCtl_cma_endpoint_label + + ; === host_name (type: Text) === + ${NSD_CreateText} 85u 1u 124u 12u "" + Pop $hCtl_cma_host_name + + ; === endpoint (type: Text) === + ${NSD_CreateText} 85u 18u 124u 12u "" + Pop $hCtl_cma_endpoint + + ; === reverse (type: Checkbox) === + ${NSD_CreateCheckbox} 8u 42u 103u 15u "Poller-initiated connection" + Pop $hCtl_cma_reverse + ${NSD_OnClick} $hCtl_cma_reverse reverse_onClick + + ; === Label15 (type: Label) === + ${NSD_CreateLabel} 8u 3u 84u 12u "Host name in Centreon:" + Pop $hCtl_cma_Label15 + + ; CreateFunctionCustomScript + Call init_setup_dlg + + +FunctionEnd + +; dialog show function +Function fnc_cma_Show + Call fnc_cma_Create + nsDialogs::Show +FunctionEnd diff --git a/agent/installer/silent.nsi b/agent/installer/silent.nsi new file mode 100644 index 00000000000..f7e0c9477dd --- /dev/null +++ b/agent/installer/silent.nsi @@ -0,0 +1,477 @@ +# +# Copyright 2024 Centreon +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# +# For more information : contact@centreon.com +# + +!include "FileFunc.nsh" + + +var cmdline_parameters +var silent_install_cma +var silent_install_plugins + +/** + * @brief write an error message to stdout and exit 1 +*/ +Function silent_fatal_error + System::Call 'kernel32::AttachConsole(i -1)i.r0' ;attach to parent console + System::Call 'kernel32::GetStdHandle(i -11)i.r0' ;console attached -- get stdout + FileWrite $0 "$1$\n" + SetErrorLevel 1 + Quit +FunctionEnd + +/** + * @brief displays all options in silent mode to stdout and exit 2 +*/ +Function show_help + + ClearErrors + ${GetOptions} $cmdline_parameters "--help" $0 + ${IfNot} ${Errors} + System::Call 'kernel32::AttachConsole(i -1)i.r0' ;attach to parent console + System::Call 'kernel32::GetStdHandle(i -11)i.r0' ;console attached -- get stdout + FileWrite $0 "usage: centreon-monitoring-agent.exe args$\n" + FileWrite $0 "This installer works into mode:$\n" + FileWrite $0 " - Without argument: interactive windows UI$\n" + FileWrite $0 " - Silent mode with the /S flag$\n" + FileWrite $0 "Silent mode arguments:$\n" + ${If} $1 != "" + FileWrite $0 "$1$\n" + ${EndIf} + FileWrite $0 "--hostname The name of the host as defined in the Centreon interface.$\n" + FileWrite $0 "--endpoint IP address of DNS name of the poller the agent will connect to.$\n" + FileWrite $0 " In case of Poller-initiated connection mode, it is the interface and port on which the agent will accept connections from the poller. 0.0.0.0 means all interfaces.$\n" + FileWrite $0 " The format is :" + FileWrite $0 "--reverse Add this flag for Poller-initiated connection mode.$\n" + FileWrite $0 "$\n" + FileWrite $0 "--log_type event_log or file. In case of logging in a file, log_file param is mandatory $\n" + FileWrite $0 "--log_level can be off, critical, error, warning, debug or trace$\n" + FileWrite $0 "--log_file log files path.$\n" + FileWrite $0 "--log_max_file_size max file in Mo before rotate. $\n" + FileWrite $0 "--log_max_files max number of log files before delete. $\n" + FileWrite $0 " For the rotation of logs to be active, it is necessary that both parameters 'Max File Size' and 'Max number of files' are set. The space used by the logs of the agent will not exceed 'Max File Size' * 'Max number of files'. $\n" + FileWrite $0 "$\n" + FileWrite $0 "--encryption Add this flag for encrypt connection with poller.$\n" + FileWrite $0 "--private_key Private key file path. Mandatory if encryption and poller-initiated connection are active.$\n" + FileWrite $0 "--public_cert Public certificate file path. Mandatory if encryption and poller-initiated connection are active.$\n" + FileWrite $0 "--ca Trusted CA's certificate file path.$\n" + FileWrite $0 "--ca_name Expected TLS certificate common name (CN). Don't use it if unsure.$\n" + SetErrorLevel 2 + Quit + ${EndIf} +FunctionEnd + + +/** + * @brief displays version in silent mode to stdout and exit 2 +*/ +Function show_version + ${GetParameters} $cmdline_parameters + + ClearErrors + ${GetOptions} $cmdline_parameters "--version" $0 + ${IfNot} ${Errors} + System::Call 'kernel32::AttachConsole(i -1)i.r0' ;attach to parent console + System::Call 'kernel32::GetStdHandle(i -11)i.r0' ;console attached -- get stdout + FileWrite $0 "Centreon Monitoring Agent installer version:${VERSIONMAJOR}.${VERSIONMINOR}.${VERSIONBUILD}$\n" + SetErrorLevel 2 + Quit + ${EndIf} +FunctionEnd + + +/** + * @brief checks if user is an admin and output an error message to stdout if not +*/ +Function silent_verify_admin + UserInfo::GetAccountType + pop $0 + ${If} $0 != "admin" ;Require admin rights + StrCpy $1 "Administrator rights required!" + Call silent_fatal_error + ${EndIf} +FunctionEnd + + +/** + * @brief fill registry with cmdline parameters + * used by installer +*/ +Function cmd_line_to_registry + StrCpy $1 ${FILE_PATH_REGEXP} + + SetRegView 64 + + #setup + ClearErrors + ${GetOptions} $cmdline_parameters "--hostname" $0 + ${If} ${Errors} + ${OrIf} $0 == "" + StrCpy $1 "Empty host name not allowed" + Call silent_fatal_error + ${EndIf} + WriteRegStr HKLM ${CMA_REG_KEY} "host" "$0" + ClearErrors + ${GetOptions} $cmdline_parameters "--endpoint" $0 + ${If} ${Errors} + ${OrIf} $0 !~ '[a-zA-Z0-9\.\-_]+:[0-9]+' + StrCpy $1 "The correct format for poller end point or listening interface is :, actual parameter is $0" + Call silent_fatal_error + ${EndIf} + WriteRegStr HKLM ${CMA_REG_KEY} "endpoint" "$0" + + ClearErrors + ${GetOptions} $cmdline_parameters "--reverse" $0 + ${If} ${Errors} + WriteRegDWORD HKLM ${CMA_REG_KEY} "reversed_grpc_streaming" 0 + Strcpy $2 0 + ${Else} + WriteRegDWORD HKLM ${CMA_REG_KEY} "reversed_grpc_streaming" 1 + Strcpy $2 1 + ${EndIf} + + #log + ClearErrors + ${GetOptions} $cmdline_parameters "--log_type" $0 + ${IfNot} ${Errors} + ${AndIf} $0 == "file" + WriteRegStr HKLM ${CMA_REG_KEY} "log_type" "File" + ClearErrors + ${GetOptions} $cmdline_parameters "--log_file" $0 + ${If} ${Errors} + ${OrIf} $0 !~ $1 + StrCpy $1 "Bad log file path, actual parameter is $0" + Call silent_fatal_error + ${EndIf} + WriteRegStr HKLM ${CMA_REG_KEY} "log_type" "file" + WriteRegStr HKLM ${CMA_REG_KEY} "log_file" $0 + + ${GetOptions} $cmdline_parameters "--log_max_file_size" $0 + ${If} ${Errors} + WriteRegDWORD HKLM ${CMA_REG_KEY} "log_max_file_size" 0 + ${Else} + WriteRegDWORD HKLM ${CMA_REG_KEY} "log_max_file_size" $0 + ${EndIf} + + ${GetOptions} $cmdline_parameters "--log_max_files" $0 + ${If} ${Errors} + WriteRegDWORD HKLM ${CMA_REG_KEY} "log_max_files" 0 + ${Else} + WriteRegDWORD HKLM ${CMA_REG_KEY} "log_max_files" $0 + ${EndIf} + + ${Else} + WriteRegStr HKLM ${CMA_REG_KEY} "log_type" "EventLog" + ${EndIf} + ClearErrors + ${GetOptions} $cmdline_parameters "--log_level" $0 + ${IfNot} ${Errors} + ${If} $0 == 'off' + ${OrIf} $0 == 'critical' + ${OrIf} $0 == 'error' + ${OrIf} $0 == 'warning' + ${OrIf} $0 == 'debug' + ${OrIf} $0 == 'trace' + ${StrCase} $0 $0 "L" + WriteRegStr HKLM ${CMA_REG_KEY} "log_level" $0 + ${Else} + Strcpy $1 "log_level must be one of off, critical, error, warning, debug or trace" + Call silent_fatal_error + ${EndIf} + ${Else} + WriteRegStr HKLM ${CMA_REG_KEY} "log_level" "error" + ${EndIf} + + #encryption + ClearErrors + ${GetOptions} $cmdline_parameters "--encryption" $0 + ${IfNot} ${Errors} + StrCpy $0 "" + ${GetOptions} $cmdline_parameters "--private_key" $0 + ${If} ${Errors} + ${If} $2 == 1 + Strcpy $1 "If encryption and poller-initiated connection are active, the private key is mandatory." + Call silent_fatal_error + ${EndIf} + ${Else} + ${If} $0 !~ $1 + Strcpy $1 "Bad private key file path." + Call silent_fatal_error + ${EndIf} + ${EndIf} + WriteRegStr HKLM ${CMA_REG_KEY} "private_key" $0 + + StrCpy $0 "" + ${GetOptions} $cmdline_parameters "--public_cert" $0 + ${If} ${Errors} + ${If} $2 == 1 + Strcpy $1 "If encryption and poller-initiated connection are active, the certificate is mandatory." + Call silent_fatal_error + ${EndIf} + ${Else} + ${If} $0 !~ $1 + Strcpy $1 "Bad certificate file path." + Call silent_fatal_error + ${EndIf} + ${EndIf} + WriteRegStr HKLM ${CMA_REG_KEY} "certificate" $0 + + StrCpy $0 "" + ${GetOptions} $cmdline_parameters "--ca" $0 + ${IfNot} ${Errors} + ${If} $0 !~ $1 + Strcpy $1 "Bad CA file path." + Call silent_fatal_error + ${EndIf} + ${EndIf} + WriteRegStr HKLM ${CMA_REG_KEY} "ca_certificate" $0 + + StrCpy $0 "" + ${GetOptions} $cmdline_parameters "--ca_name" $0 + WriteRegStr HKLM ${CMA_REG_KEY} "ca_name" $0 + WriteRegDWORD HKLM ${CMA_REG_KEY} "encryption" 1 + ${Else} + WriteRegDWORD HKLM ${CMA_REG_KEY} "encryption" 0 + ${EndIf} + +FunctionEnd + +/** + * @brief fill registry with cmdline parameters + * used by conf updater/modifier +*/ +Function silent_update_conf + StrCpy $1 ${FILE_PATH_REGEXP} + + SetRegView 64 + + #setup + ClearErrors + ${GetOptions} $cmdline_parameters "--hostname" $0 + ${IfNot} ${Errors} + WriteRegStr HKLM ${CMA_REG_KEY} "host" "$0" + ${EndIf} + ClearErrors + ${GetOptions} $cmdline_parameters "--endpoint" $0 + ${IfNot} ${Errors} + ${If} $0 !~ '[a-zA-Z0-9\.\-_]+:[0-9]+' + StrCpy $1 "The correct format for poller end point or listening interface is :" + Call silent_fatal_error + ${EndIf} + WriteRegStr HKLM ${CMA_REG_KEY} "endpoint" "$0" + ${EndIf} + ClearErrors + ${GetOptions} $cmdline_parameters "--reverse" $0 + ${IfNot} ${Errors} + WriteRegDWORD HKLM ${CMA_REG_KEY} "reversed_grpc_streaming" 1 + ${EndIf} + ClearErrors + ${GetOptions} $cmdline_parameters "--no_reverse" $0 + ${IfNot} ${Errors} + WriteRegDWORD HKLM ${CMA_REG_KEY} "reversed_grpc_streaming" 0 + ${EndIf} + + #log + ClearErrors + ${GetOptions} $cmdline_parameters "--log_type" $0 + ${IfNot} ${Errors} + ${If} $0 == "file" + WriteRegStr HKLM ${CMA_REG_KEY} "log_type" "file" + ${Else} + WriteRegStr HKLM ${CMA_REG_KEY} "log_type" "event-log" + ${EndIf} + ${EndIf} + ReadRegStr $0 HKLM ${CMA_REG_KEY} "log_type" + ${If} $0 == "file" + ClearErrors + ${GetOptions} $cmdline_parameters "--log_file" $0 + ${IfNot} ${Errors} + ${If} $0 !~ $1 + StrCpy $1 "Bad log file path" + Call silent_fatal_error + ${EndIf} + WriteRegStr HKLM ${CMA_REG_KEY} "log_file" $0 + ${EndIf} + ClearErrors + ${GetOptions} $cmdline_parameters "--log_max_file_size" $0 + ${IfNot} ${Errors} + WriteRegDWORD HKLM ${CMA_REG_KEY} "log_max_file_size" $0 + ${EndIf} + ${GetOptions} $cmdline_parameters "--log_max_files" $0 + ${IfNot} ${Errors} + WriteRegDWORD HKLM ${CMA_REG_KEY} "log_max_files" $0 + ${EndIf} + ${EndIf} + ClearErrors + ${GetOptions} $cmdline_parameters "--log_level" $0 + ${IfNot} ${Errors} + ${If} $0 == 'off' + ${OrIf} $0 == 'critical' + ${OrIf} $0 == 'error' + ${OrIf} $0 == 'warning' + ${OrIf} $0 == 'debug' + ${OrIf} $0 == 'trace' + ${StrCase} $0 $0 "L" + WriteRegStr HKLM ${CMA_REG_KEY} "log_level" $0 + ${Else} + Strcpy $1 "log_level must be one of off, critical, error, warning, debug or trace" + Call silent_fatal_error + ${EndIf} + ${EndIf} + + #encryption + ClearErrors + ${GetOptions} $cmdline_parameters "--encryption" $0 + ${IfNot} ${Errors} + WriteRegDWORD HKLM ${CMA_REG_KEY} "encryption" 0 + ${EndIf} + ReadRegDWORD $0 HKLM ${CMA_REG_KEY} "encryption" + ${If} $0 > 0 + ${GetOptions} $cmdline_parameters "--private_key" $0 + ${IfNot} ${Errors} + ${If} $0 !~ $1 + Strcpy $1 "Bad private key file path." + Call silent_fatal_error + ${EndIf} + WriteRegStr HKLM ${CMA_REG_KEY} "private_key" $0 + ${EndIf} + ${GetOptions} $cmdline_parameters "--public_cert" $0 + ${IfNot} ${Errors} + ${If} $0 !~ $1 + Strcpy $1 "Bad certificate file path." + Call silent_fatal_error + ${EndIf} + WriteRegStr HKLM ${CMA_REG_KEY} "certificate" $0 + ${EndIf} + ${GetOptions} $cmdline_parameters "--ca" $0 + ${IfNot} ${Errors} + ${If} $0 !~ $1 + Strcpy $1 "Bad CA file path." + Call silent_fatal_error + ${EndIf} + WriteRegStr HKLM ${CMA_REG_KEY} "ca_certificate" $0 + ${EndIf} + + ${GetOptions} $cmdline_parameters "--ca_name" $0 + ${IfNot} ${Errors} + WriteRegStr HKLM ${CMA_REG_KEY} "ca_name" $0 + ${EndIf} + + WriteRegDWORD HKLM ${CMA_REG_KEY} "encryption" 1 + ${EndIf} + + ClearErrors + ${GetOptions} $cmdline_parameters "--no_encryption" $0 + ${IfNot} ${Errors} + WriteRegDWORD HKLM ${CMA_REG_KEY} "encryption" 0 + ${EndIf} + + #certif and private key are mandatory in reverse mode + ReadRegDWORD $0 HKLM ${CMA_REG_KEY} "reversed_grpc_streaming" + ${If} $0 > 0 + ReadRegDWORD $0 HKLM ${CMA_REG_KEY} "encryption" + ${If} $0 > 0 + ReadRegStr $0 HKLM ${CMA_REG_KEY} "private_key" + ${If} $0 == "" + WriteRegDWORD HKLM ${CMA_REG_KEY} "encryption" 0 + Strcpy $1 "If encryption and poller-initiated connection are active, the private key is mandatory." + Call silent_fatal_error + ${EndIf} + ReadRegStr $0 HKLM ${CMA_REG_KEY} "certificate" + ${If} $0 == "" + WriteRegDWORD HKLM ${CMA_REG_KEY} "encryption" 0 + Strcpy $1 "If encryption and poller-initiated connection are active, the certificate is mandatory." + Call silent_fatal_error + ${EndIf} + ${EndIf} + ${EndIf} + + +FunctionEnd + +/** + * @brief checks --install_plugins and --install_cma cmdline flags +*/ +Function installer_parse_cmd_line + Push $0 + + ClearErrors + ${GetOptions} $cmdline_parameters "--install_plugins" $0 + ${IfNot} ${Errors} + StrCpy $silent_install_plugins 1 + ${EndIf} + + ClearErrors + ${GetOptions} $cmdline_parameters "--install_cma" $0 + ${IfNot} ${Errors} + StrCpy $silent_install_cma 1 + ${EndIf} + + Pop $0 +FunctionEnd + + +/** + * @brief display help uninstaller +*/ +Function un.show_uninstaller_help + ClearErrors + ${GetOptions} $cmdline_parameters "--help" $0 + ${IfNot} ${Errors} + System::Call 'kernel32::AttachConsole(i -1)i.r0' ;attach to parent console + System::Call 'kernel32::GetStdHandle(i -11)i.r0' ;console attached -- get stdout + FileWrite $0 "usage: uninstaller.exe args$\n" + FileWrite $0 "Silent mode arguments:$\n" + FileWrite $0 "--uninstall_cma uninstall centreon-monitoring-agent$\n" + FileWrite $0 "--uninstall_plugins uninstall Centreon plugins$\n" + SetErrorLevel 2 + Quit + ${EndIf} +FunctionEnd + + +/** + * @brief display uninstaller version +*/ +Function un.show_version + ${GetParameters} $cmdline_parameters + + ClearErrors + ${GetOptions} $cmdline_parameters "--version" $0 + ${IfNot} ${Errors} + System::Call 'kernel32::AttachConsole(i -1)i.r0' ;attach to parent console + System::Call 'kernel32::GetStdHandle(i -11)i.r0' ;console attached -- get stdout + FileWrite $0 "Centreon Monitoring Agent uninstaller version:${VERSIONMAJOR}.${VERSIONMINOR}.${VERSIONBUILD}$\n" + SetErrorLevel 2 + Quit + ${EndIf} +FunctionEnd + +/** + * @brief checks if user is an admin and output an error message to stdout if not +*/ +Function un.silent_verify_admin + UserInfo::GetAccountType + pop $0 + ${If} $0 != "admin" ;Require admin rights + System::Call 'kernel32::AttachConsole(i -1)i.r0' ;attach to parent console + System::Call 'kernel32::GetStdHandle(i -11)i.r0' ;console attached -- get stdout + FileWrite $0 "Administrator rights required!$\n" + SetErrorLevel 1 + Quit + ${EndIf} +FunctionEnd \ No newline at end of file diff --git a/agent/installer/version.nsi.in b/agent/installer/version.nsi.in new file mode 100644 index 00000000000..7ccd0fc0528 --- /dev/null +++ b/agent/installer/version.nsi.in @@ -0,0 +1,22 @@ +# +# Copyright 2024 Centreon +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# +# For more information : contact@centreon.com +# + +!define VERSIONMAJOR ${COLLECT_MAJOR} +!define VERSIONMINOR ${COLLECT_MINOR} +!define VERSIONBUILD ${COLLECT_PATCH} +!define CENTAGENT_PATH "${CENTAGENT_PATH}" \ No newline at end of file diff --git a/agent/native_linux/inc/com/centreon/agent/check_cpu.hh b/agent/native_linux/inc/com/centreon/agent/check_cpu.hh new file mode 100644 index 00000000000..f11f02b039e --- /dev/null +++ b/agent/native_linux/inc/com/centreon/agent/check_cpu.hh @@ -0,0 +1,24 @@ +/** + * Copyright 2024 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ + +#ifndef CENTREON_AGENT_CHECK_CPU_HH +#define CENTREON_AGENT_CHECK_CPU_HH + +namespace com::centreon::agent {} + +#endif diff --git a/agent/native_linux/src/check_cpu.cc b/agent/native_linux/src/check_cpu.cc new file mode 100644 index 00000000000..ff1a150ce8e --- /dev/null +++ b/agent/native_linux/src/check_cpu.cc @@ -0,0 +1 @@ +class dummy{}; diff --git a/agent/native_windows/inc/com/centreon/agent/check_cpu.hh b/agent/native_windows/inc/com/centreon/agent/check_cpu.hh new file mode 100644 index 00000000000..f11f02b039e --- /dev/null +++ b/agent/native_windows/inc/com/centreon/agent/check_cpu.hh @@ -0,0 +1,24 @@ +/** + * Copyright 2024 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ + +#ifndef CENTREON_AGENT_CHECK_CPU_HH +#define CENTREON_AGENT_CHECK_CPU_HH + +namespace com::centreon::agent {} + +#endif diff --git a/agent/native_windows/src/check_cpu.cc b/agent/native_windows/src/check_cpu.cc new file mode 100644 index 00000000000..e69de29bb2d diff --git a/agent/precomp_inc/precomp.hh b/agent/precomp_inc/precomp.hh index 8c9b04fb62a..cffb6f5b781 100644 --- a/agent/precomp_inc/precomp.hh +++ b/agent/precomp_inc/precomp.hh @@ -42,4 +42,6 @@ namespace asio = boost::asio; #include #include +#include + #endif diff --git a/agent/src/agent.rc.in b/agent/src/agent.rc.in new file mode 100644 index 00000000000..86739dae065 --- /dev/null +++ b/agent/src/agent.rc.in @@ -0,0 +1,28 @@ +1 VERSIONINFO + FILEVERSION ${COLLECT_MAJOR},${COLLECT_MINOR},${COLLECT_PATCH} + PRODUCTVERSION ${COLLECT_MAJOR},${COLLECT_MINOR},${COLLECT_PATCH} + FILEFLAGSMASK 0x17L + FILEFLAGS 0x0L + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080904b0" + BEGIN + VALUE "CompanyName", "Centreon" + VALUE "FileDescription", "Centreon Monitoring Agent" + VALUE "FileVersion", "${COLLECT_MAJOR}.${COLLECT_MINOR}.${COLLECT_PATCH}" + VALUE "InternalName", "centagent.exe" + VALUE "LegalCopyright", "2024 Centreon" + VALUE "OriginalFilename", "centagent.exe" + VALUE "ProductName", "Centreon Monitoring Agent" + VALUE "ProductVersion", "${COLLECT_MAJOR}.${COLLECT_MINOR}.${COLLECT_PATCH}" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x809, 1200 + END +END diff --git a/agent/src/main_win.cc b/agent/src/main_win.cc index 05ba6276b17..e551c5164fa 100644 --- a/agent/src/main_win.cc +++ b/agent/src/main_win.cc @@ -15,6 +15,7 @@ * * For more information : contact@centreon.com */ +#include #include #include @@ -27,6 +28,8 @@ using namespace com::centreon::agent; +#define SERVICE_NAME "CentreonMonitoringAgent" + std::shared_ptr g_io_context = std::make_shared(); @@ -37,6 +40,26 @@ static std::shared_ptr _streaming_server; static asio::signal_set _signals(*g_io_context, SIGTERM, SIGINT); +/** + * @brief shutdown network connections and stop asio service + * + */ +static void stop_process() { + if (_streaming_client) { + _streaming_client->shutdown(); + } + if (_streaming_server) { + _streaming_server->shutdown(); + } + g_io_context->post([]() { g_io_context->stop(); }); +} + +/** + * @brief called on Ctrl+C + * + * @param error + * @param signal_number + */ static void signal_handler(const boost::system::error_code& error, int signal_number) { if (!error) { @@ -44,19 +67,19 @@ static void signal_handler(const boost::system::error_code& error, case SIGINT: case SIGTERM: SPDLOG_LOGGER_INFO(g_logger, "SIGTERM or SIGINT received"); - if (_streaming_client) { - _streaming_client->shutdown(); - } - if (_streaming_server) { - _streaming_server->shutdown(); - } - g_io_context->post([]() { g_io_context->stop(); }); + stop_process(); return; } _signals.async_wait(signal_handler); } } +/** + * @brief load file in a std::string + * + * @param file_path file path + * @return std::string file content + */ static std::string read_file(const std::string& file_path) { if (file_path.empty()) { return {}; @@ -75,8 +98,15 @@ static std::string read_file(const std::string& file_path) { return ""; } -int main(int argc, char* argv[]) { - const char* registry_path = "SOFTWARE\\Centreon\\CentreonMonitoringAgent"; +/** + * @brief this program can be started in two ways + * from command line: main function + * from service manager: SvcMain function + * + * @return int exit status returned to command line (0 success) + */ +int _main(bool service_start) { + const char* registry_path = "SOFTWARE\\Centreon\\" SERVICE_NAME; std::unique_ptr conf; try { @@ -87,13 +117,16 @@ int main(int argc, char* argv[]) { return 1; } - SPDLOG_INFO("centreon-monitoring-agent start"); + if (service_start) + SPDLOG_INFO("centreon-monitoring-agent service start"); + else + SPDLOG_INFO("centreon-monitoring-agent start"); const std::string logger_name = "centreon-monitoring-agent"; auto create_event_logger = []() { - auto sink = std::make_shared( - "CentreonMonitoringAgent"); + auto sink = + std::make_shared(SERVICE_NAME); g_logger = std::make_shared("", sink); }; @@ -170,3 +203,126 @@ int main(int argc, char* argv[]) { return 0; } + +/************************************************************************************** + service part +**************************************************************************************/ + +static SERVICE_STATUS gSvcStatus; +static SERVICE_STATUS_HANDLE gSvcStatusHandle; +static HANDLE ghSvcStopEvent = NULL; +void WINAPI SvcMain(DWORD, LPTSTR*); + +/** + * @brief main used when program is launched on command line + * if program is sued with --standalone flag, it does not register in service + * manager + * + * @param argc not used + * @param argv not used + * @return int program status + */ +int main(int argc, char* argv[]) { + if (argc > 1 && !lstrcmpi(argv[1], "--standalone")) { + return _main(false); + } + + SERVICE_TABLE_ENTRY DispatchTable[] = { + {SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)SvcMain}, {NULL, NULL}}; + + // This call returns when the service has stopped. + // The process should simply terminate when the call returns. + StartServiceCtrlDispatcher(DispatchTable); + + return 0; +} + +/** + * @brief Sets the current service status and reports it to the service manager. + * + * @param dwCurrentState The current state (see SERVICE_STATUS) + * @param dwWin32ExitCode The system error code + * @param dwWaitHint Estimated time for pending operation in milliseconds + */ +void report_svc_status(DWORD dwCurrentState, + DWORD dwWin32ExitCode, + DWORD dwWaitHint) { + static DWORD dwCheckPoint = 1; + + // Fill in the SERVICE_STATUS structure. + + gSvcStatus.dwCurrentState = dwCurrentState; + gSvcStatus.dwWin32ExitCode = dwWin32ExitCode; + gSvcStatus.dwWaitHint = dwWaitHint; + + if (dwCurrentState == SERVICE_START_PENDING) + gSvcStatus.dwControlsAccepted = 0; + else + gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; + + if ((dwCurrentState == SERVICE_RUNNING) || + (dwCurrentState == SERVICE_STOPPED)) + gSvcStatus.dwCheckPoint = 0; + else + gSvcStatus.dwCheckPoint = dwCheckPoint++; + + // Report the status of the service to the SCM. + SetServiceStatus(gSvcStatusHandle, &gSvcStatus); +} + +/** + * @brief function called by service manager + * + * @param dwCtrl -control code sent by service manager + */ +void WINAPI SvcCtrlHandler(DWORD dwCtrl) { + // Handle the requested control code. + + SPDLOG_LOGGER_INFO(g_logger, "SvcCtrlHandler {}", dwCtrl); + + switch (dwCtrl) { + case SERVICE_CONTROL_STOP: + report_svc_status(SERVICE_STOP_PENDING, NO_ERROR, 0); + + SPDLOG_LOGGER_INFO(g_logger, "SERVICE_CONTROL_STOP received"); + stop_process(); + + report_svc_status(gSvcStatus.dwCurrentState, NO_ERROR, 0); + + return; + + case SERVICE_CONTROL_INTERROGATE: + break; + + default: + break; + } +} + +/** + * @brief main called by service manager + * + */ +void WINAPI SvcMain(DWORD, LPTSTR*) { + gSvcStatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, SvcCtrlHandler); + + if (!gSvcStatusHandle) { + SPDLOG_LOGGER_CRITICAL(g_logger, "fail to RegisterServiceCtrlHandler"); + return; + } + + // These SERVICE_STATUS members remain as set here + + gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + gSvcStatus.dwServiceSpecificExitCode = 0; + + // Report initial status to the SCM + + report_svc_status(SERVICE_START_PENDING, NO_ERROR, 3000); + + report_svc_status(SERVICE_RUNNING, NO_ERROR, 0); + + _main(true); + + report_svc_status(SERVICE_STOPPED, NO_ERROR, 0); +} diff --git a/agent/src/scheduler.cc b/agent/src/scheduler.cc index a08749884c2..42b30224b8c 100644 --- a/agent/src/scheduler.cc +++ b/agent/src/scheduler.cc @@ -17,7 +17,10 @@ */ #include "scheduler.hh" +#include "check_exec.hh" +#include "com/centreon/common/rapidjson_helper.hh" #include "com/centreon/common/utf8.hh" +#include "com/centreon/exceptions/msg_fmt.hh" using namespace com::centreon::agent; @@ -188,9 +191,9 @@ void scheduler::update(const engine_to_agent_request_ptr& conf) { _check_queue.emplace(check_to_schedule); next += check_interval; } catch (const std::exception& e) { - SPDLOG_LOGGER_ERROR(_logger, - "service: {} command:{} won't be scheduled", - serv.service_description(), serv.command_name()); + SPDLOG_LOGGER_ERROR( + _logger, "service: {} command:{} won't be scheduled cause: {}", + serv.service_description(), serv.command_name(), e.what()); } } } @@ -490,3 +493,46 @@ void scheduler::_add_exemplar( attrib->set_key(label); exemplar->set_as_int(value); } + +/** + * @brief build a check object from command lline + * + * @param io_context + * @param logger logger that will be used by the check + * @param start_expected timepoint of first check + * @param service + * @param cmd_name + * @param cmd_line + * @param conf conf given by engine + * @param handler handler that will be called on check completion + * @return std::shared_ptr + */ +std::shared_ptr scheduler::default_check_builder( + const std::shared_ptr& io_context, + const std::shared_ptr& logger, + time_point start_expected, + const std::string& service, + const std::string& cmd_name, + const std::string& cmd_line, + const engine_to_agent_request_ptr& conf, + check::completion_handler&& handler) { + using namespace std::literals; + // test native checks where cmd_lin is a json + try { + rapidjson::Document native_check_info = + common::rapidjson_helper::read_from_string(cmd_line); + common::rapidjson_helper native_params(native_check_info); + std::string_view check_type = native_params.get_string("check"); + const rapidjson::Value& args = native_params.get_member("args"); + + if (check_type == "cpu"sv) { + } else { + throw exceptions::msg_fmt("command {}, unknown native check:{}", cmd_name, + cmd_line); + } + + } catch (const std::exception&) { + return check_exec::load(io_context, logger, start_expected, service, + cmd_name, cmd_line, conf, std::move(handler)); + } +} diff --git a/agent/src/streaming_client.cc b/agent/src/streaming_client.cc index 764f9be5769..ab38cc67717 100644 --- a/agent/src/streaming_client.cc +++ b/agent/src/streaming_client.cc @@ -119,7 +119,7 @@ void streaming_client::_start() { parent->_send(request); } }, - check_exec::load); + scheduler::default_check_builder); _create_reactor(); } diff --git a/agent/src/streaming_server.cc b/agent/src/streaming_server.cc index 06a637e8b94..681ce348a25 100644 --- a/agent/src/streaming_server.cc +++ b/agent/src/streaming_server.cc @@ -83,7 +83,7 @@ void server_reactor::_start() { parent->write(request); } }, - check_exec::load); + scheduler::default_check_builder); // identifies to engine std::shared_ptr who_i_am = diff --git a/agent/test/scripts/sleep.bat b/agent/test/scripts/sleep.bat index 9b178637c61..0866e1576ff 100644 --- a/agent/test/scripts/sleep.bat +++ b/agent/test/scripts/sleep.bat @@ -1,2 +1,2 @@ @echo off -ping 127.0.0.1 -n1 %~1 \ No newline at end of file +ping 127.0.0.1 -n1 %~1 diff --git a/bbdo/bam.proto b/bbdo/bam.proto index a51e7fd7bdf..2af2a3d0a90 100644 --- a/bbdo/bam.proto +++ b/bbdo/bam.proto @@ -29,14 +29,14 @@ enum State { UNKNOWN = 3; } -/*io::bam, bam::de_pb_inherited_downtime*/ +/* io::bam, bam::de_pb_inherited_downtime, 31 */ message InheritedDowntime { BBDOHeader header = 1; uint32 ba_id = 2; bool in_downtime = 3; } -/*io::bam, bam::de_pb_ba_status*/ +/* io::bam, bam::de_pb_ba_status, 32 */ message BaStatus { uint32 ba_id = 1; bool in_downtime = 2; @@ -49,17 +49,17 @@ message BaStatus { string output = 9; } -/*io::bam, bam::de_pb_ba_event*/ +/* io::bam, bam::de_pb_ba_event, 33 */ message BaEvent { uint32 ba_id = 1; double first_level = 2; - int64 end_time = 3; + uint64 end_time = 3; bool in_downtime = 4; uint64 start_time = 5; State status = 6; } -/*io::bam, bam::de_pb_kpi_event*/ +/* io::bam, bam::de_pb_kpi_event, 34 */ message KpiEvent { uint32 ba_id = 1; uint64 start_time = 2; @@ -72,20 +72,20 @@ message KpiEvent { State status = 9; } -/*io::bam, bam::de_pb_dimension_bv_event*/ +/* io::bam, bam::de_pb_dimension_bv_event, 35 */ message DimensionBvEvent { uint32 bv_id = 1; string bv_name = 2; string bv_description = 3; } -/*io::bam, bam::de_pb_dimension_ba_bv_relation_event*/ +/* io::bam, bam::de_pb_dimension_ba_bv_relation_event, 36 */ message DimensionBaBvRelationEvent { uint32 ba_id = 1; uint32 bv_id = 2; } -/*io::bam, bam::de_pb_dimension_timeperiod*/ +/* io::bam, bam::de_pb_dimension_timeperiod, 37 */ message DimensionTimeperiod { uint32 id = 1; string name = 2; @@ -98,7 +98,7 @@ message DimensionTimeperiod { string sunday = 9; } -/*io::bam, bam::de_pb_dimension_ba_event*/ +/* io::bam, bam::de_pb_dimension_ba_event, 38 */ message DimensionBaEvent { uint32 ba_id = 1; string ba_name = 2; @@ -109,7 +109,7 @@ message DimensionBaEvent { uint32 sla_duration_warn = 7; } -/*io::bam, bam::de_pb_dimension_kpi_event*/ +/* io::bam, bam::de_pb_dimension_kpi_event, 39 */ message DimensionKpiEvent { uint32 kpi_id = 1; uint32 ba_id = 2; @@ -129,7 +129,7 @@ message DimensionKpiEvent { double impact_unknown = 16; } -/*io::bam, bam::de_pb_kpi_status*/ +/* io::bam, bam::de_pb_kpi_status, 40 */ message KpiStatus { uint32 kpi_id = 1; bool in_downtime = 2; @@ -146,7 +146,7 @@ message KpiStatus { bool valid = 13; } -/*io::bam, bam::de_pb_ba_duration_event*/ +/* io::bam, bam::de_pb_ba_duration_event, 41 */ message BaDurationEvent { uint32 ba_id = 1; int64 real_start_time = 2; @@ -158,14 +158,14 @@ message BaDurationEvent { bool timeperiod_is_default = 8; } -/*io::bam, bam::de_pb_dimension_ba_timeperiod_relation*/ +/* io::bam, bam::de_pb_dimension_ba_timeperiod_relation, 42 */ message DimensionBaTimeperiodRelation { uint32 ba_id = 1; uint32 timeperiod_id = 2; bool is_default = 3; } -/*io::bam, bam::de_pb_dimension_truncate_table_signal*/ +/* io::bam, bam::de_pb_dimension_truncate_table_signal, 43 */ message DimensionTruncateTableSignal { bool update_started = 1; } diff --git a/bbdo/bam/ba_status.hh b/bbdo/bam/ba_status.hh index 209ee02258c..a946473bfd1 100644 --- a/bbdo/bam/ba_status.hh +++ b/bbdo/bam/ba_status.hh @@ -19,9 +19,7 @@ #ifndef CCB_BAM_BA_STATUS_HH #define CCB_BAM_BA_STATUS_HH -#include "bbdo/events.hh" #include "com/centreon/broker/io/data.hh" -#include "com/centreon/broker/io/event_info.hh" #include "com/centreon/broker/io/events.hh" #include "com/centreon/broker/mapping/entry.hh" #include "com/centreon/broker/timestamp.hh" diff --git a/bbdo/bam/dimension_ba_bv_relation_event.hh b/bbdo/bam/dimension_ba_bv_relation_event.hh index 1b79c87d2f1..c512bed7c3d 100644 --- a/bbdo/bam/dimension_ba_bv_relation_event.hh +++ b/bbdo/bam/dimension_ba_bv_relation_event.hh @@ -19,9 +19,7 @@ #ifndef CCB_BAM_DIMENSION_BA_BV_RELATION_EVENT_HH #define CCB_BAM_DIMENSION_BA_BV_RELATION_EVENT_HH -#include "bbdo/events.hh" #include "com/centreon/broker/io/data.hh" -#include "com/centreon/broker/io/event_info.hh" #include "com/centreon/broker/io/events.hh" #include "com/centreon/broker/mapping/entry.hh" #include "com/centreon/broker/timestamp.hh" diff --git a/bbdo/bam/dimension_ba_event.hh b/bbdo/bam/dimension_ba_event.hh index ac1ea83057a..646a95b69b4 100644 --- a/bbdo/bam/dimension_ba_event.hh +++ b/bbdo/bam/dimension_ba_event.hh @@ -19,9 +19,7 @@ #ifndef CCB_BAM_DIMENSION_BA_EVENT_HH #define CCB_BAM_DIMENSION_BA_EVENT_HH -#include "bbdo/events.hh" #include "com/centreon/broker/io/data.hh" -#include "com/centreon/broker/io/event_info.hh" #include "com/centreon/broker/io/events.hh" #include "com/centreon/broker/mapping/entry.hh" #include "com/centreon/broker/timestamp.hh" diff --git a/bbdo/bam/dimension_bv_event.hh b/bbdo/bam/dimension_bv_event.hh index 3ee958b42e9..2a912d0c4fe 100644 --- a/bbdo/bam/dimension_bv_event.hh +++ b/bbdo/bam/dimension_bv_event.hh @@ -19,9 +19,7 @@ #ifndef CCB_BAM_DIMENSION_BV_EVENT_HH #define CCB_BAM_DIMENSION_BV_EVENT_HH -#include "bbdo/events.hh" #include "com/centreon/broker/io/data.hh" -#include "com/centreon/broker/io/event_info.hh" #include "com/centreon/broker/io/events.hh" #include "com/centreon/broker/mapping/entry.hh" #include "com/centreon/broker/timestamp.hh" diff --git a/bbdo/bam/dimension_truncate_table_signal.hh b/bbdo/bam/dimension_truncate_table_signal.hh index adf2107af4c..e8e50491987 100644 --- a/bbdo/bam/dimension_truncate_table_signal.hh +++ b/bbdo/bam/dimension_truncate_table_signal.hh @@ -19,9 +19,7 @@ #ifndef CCB_BAM_DIMENSION_TRUNCATE_TABLE_SIGNAL_HH #define CCB_BAM_DIMENSION_TRUNCATE_TABLE_SIGNAL_HH -#include "bbdo/events.hh" #include "com/centreon/broker/io/data.hh" -#include "com/centreon/broker/io/event_info.hh" #include "com/centreon/broker/io/events.hh" #include "com/centreon/broker/mapping/entry.hh" #include "com/centreon/broker/timestamp.hh" diff --git a/bbdo/bam/kpi_status.hh b/bbdo/bam/kpi_status.hh index 77b2c225aa0..1de9adedc74 100644 --- a/bbdo/bam/kpi_status.hh +++ b/bbdo/bam/kpi_status.hh @@ -19,9 +19,7 @@ #ifndef CCB_BAM_KPI_STATUS_HH #define CCB_BAM_KPI_STATUS_HH -#include "bbdo/events.hh" #include "com/centreon/broker/io/data.hh" -#include "com/centreon/broker/io/event_info.hh" #include "com/centreon/broker/io/events.hh" #include "com/centreon/broker/mapping/entry.hh" #include "com/centreon/broker/timestamp.hh" diff --git a/bbdo/bam/rebuild.hh b/bbdo/bam/rebuild.hh index b965bcf3ec7..09e3a6e5f09 100644 --- a/bbdo/bam/rebuild.hh +++ b/bbdo/bam/rebuild.hh @@ -19,9 +19,7 @@ #ifndef CCB_BAM_REBUILD_HH #define CCB_BAM_REBUILD_HH -#include "bbdo/events.hh" #include "com/centreon/broker/io/data.hh" -#include "com/centreon/broker/io/event_info.hh" #include "com/centreon/broker/io/events.hh" #include "com/centreon/broker/mapping/entry.hh" diff --git a/bbdo/bam_state.proto b/bbdo/bam_state.proto index 19a567c4f58..5db522dcfb6 100644 --- a/bbdo/bam_state.proto +++ b/bbdo/bam_state.proto @@ -26,6 +26,7 @@ package com.centreon.broker; * @brief Stores needed information for bool_service or kpi_service. Very useful * when broker is stopped to save the BA's states. */ +/* Ignore */ message ServiceState { uint64 host_id = 1; uint64 service_id = 2; @@ -40,7 +41,7 @@ message ServiceState { * @brief This message contains the living informations of the current BA's. * Thanks to them we can recompute their states when Broker is restarted. */ -/*io::bam, bam::de_pb_services_book_state*/ +/* io::bam, bam::de_pb_services_book_state, 48 */ message ServicesBookState { repeated ServiceState service = 1; } diff --git a/bbdo/bbdo.proto b/bbdo/bbdo.proto index a9823ccaf81..ee3ffa21a07 100644 --- a/bbdo/bbdo.proto +++ b/bbdo/bbdo.proto @@ -20,14 +20,14 @@ syntax = "proto3"; package com.centreon.broker; - +/* Ignore */ message Bbdo { uint32 major = 1; uint32 minor = 2; uint32 patch = 3; } -/*io::bbdo, bbdo::de_welcome*/ +/* io::bbdo, bbdo::de_welcome, 49 */ message Welcome { Bbdo version = 1; string extensions = 2; @@ -35,12 +35,12 @@ message Welcome { string poller_name = 4; } -/*io::bbdo, bbdo::de_pb_ack*/ +/* io::bbdo, bbdo::de_pb_ack, 50 */ message Ack { uint32 acknowledged_events = 1; } -/*io::bbdo, bbdo::de_pb_stop*/ +/* io::bbdo, bbdo::de_pb_stop, 51 */ message Stop { uint64 poller_id = 1; } diff --git a/bbdo/events.hh b/bbdo/events.hh index 5e392018328..9585bd26055 100644 --- a/bbdo/events.hh +++ b/bbdo/events.hh @@ -152,7 +152,9 @@ enum data_element { de_pb_service_group = 51, de_pb_service_group_member = 52, de_pb_host_parent = 53, - de_pb_instance_configuration = 54 + de_pb_instance_configuration = 54, + de_pb_adaptive_service_status = 55, + de_pb_adaptive_host_status = 56, }; } // namespace neb namespace storage { diff --git a/bbdo/extcmd.proto b/bbdo/extcmd.proto index f0cadaf0397..3a5bdf186c9 100644 --- a/bbdo/extcmd.proto +++ b/bbdo/extcmd.proto @@ -23,7 +23,7 @@ import "google/protobuf/timestamp.proto"; package com.centreon.broker; - +/* Ignore */ message TimePoint { string name = 1; string function = 2; @@ -36,7 +36,7 @@ message TimePoint { * from engine to dest with several timepoints (one per muxer) * */ -/*io::extcmd, extcmd::de_pb_bench*/ +/* io::extcmd, extcmd::de_pb_bench, 3 */ message Bench { uint32 id = 1; repeated TimePoint points = 2; diff --git a/bbdo/neb.proto b/bbdo/neb.proto index b4603072255..a5c4715c630 100644 --- a/bbdo/neb.proto +++ b/bbdo/neb.proto @@ -40,7 +40,7 @@ enum AckType { STICKY = 2; } -/*io::neb, neb::de_pb_service*/ +/* io::neb, neb::de_pb_service, 5 */ message Service { uint64 host_id = 1; uint64 service_id = 2; @@ -155,10 +155,25 @@ message Service { uint64 icon_id = 87; } +/** + * @brief Message sent in BBDO 3.0.0 to update a service status partially + * changed. For example, it is convenient for downtime changed. + */ +/* io::neb, neb::de_pb_adaptive_service_status, 53 */ +message AdaptiveServiceStatus { + uint64 host_id = 1; + uint64 service_id = 2; + ServiceType type = 3; + uint64 internal_id = 4; + optional int32 scheduled_downtime_depth = 5; + optional AckType acknowledgement_type = 6; + optional int32 notification_number = 7; +} + /** * @brief Message sent in BBDO 3.0.0 instead of neb::service_status */ -/*io::neb, neb::de_pb_service_status*/ +/* io::neb, neb::de_pb_service_status, 6 */ message ServiceStatus { uint64 host_id = 1; uint64 service_id = 2; @@ -225,7 +240,7 @@ message ServiceStatus { * * Only used with BBDO 3.0 */ -/*io::neb, neb::de_pb_adaptive_service*/ +/* io::neb, neb::de_pb_adaptive_service, 7 */ message AdaptiveService { uint64 host_id = 1; uint64 service_id = 2; @@ -247,7 +262,7 @@ message AdaptiveService { optional string notification_period = 17; } -/*io::neb, neb::de_pb_host*/ +/* io::neb, neb::de_pb_host, 8 */ message Host { uint64 host_id = 1; @@ -354,7 +369,7 @@ message Host { /** * @brief Message sent in BBDO 3.0.0 instead of neb::service_status */ -/*io::neb, neb::de_pb_host_status*/ +/* io::neb, neb::de_pb_host_status, 9 */ message HostStatus { uint64 host_id = 1; @@ -405,13 +420,24 @@ message HostStatus { int32 scheduled_downtime_depth = 28; } +/** + * @brief Message sent in BBDO 3.0.0 to update a host status partially + * changed. For example, it is convenient for downtime changed. + */ +/* io::neb, neb::de_pb_adaptive_host_status, 55 */ +message AdaptiveHostStatus { + uint64 host_id = 1; + optional int32 scheduled_downtime_depth = 2; + optional AckType acknowledgement_type = 3; + optional int32 notification_number = 4; +} /** * @brief Message used to send adaptive host configuration. When only one * or two configuration items change, this event is used. * * Only used with BBDO 3.0 */ -/*io::neb, neb::de_pb_adaptive_host*/ +/* io::neb, neb::de_pb_adaptive_host, 10 */ message AdaptiveHost { uint64 host_id = 1; @@ -432,7 +458,7 @@ message AdaptiveHost { optional string notification_period = 16; } -/*io::neb, neb::de_pb_comment*/ +/* io::neb, neb::de_pb_comment, 11 */ message Comment { BBDOHeader header = 1; @@ -475,7 +501,7 @@ message Comment { * @brief A downtime is applied on a resource when we don't want notifications * concerning bad states on this resource. */ -/*io::neb, neb::de_pb_downtime*/ +/* io::neb, neb::de_pb_downtime, 12 */ message Downtime { enum DowntimeType { NOT_USED = 0; @@ -503,7 +529,7 @@ message Downtime { bool fixed = 18; } -/*io::neb, neb::de_pb_custom_variable*/ +/* io::neb, neb::de_pb_custom_variable, 13 */ message CustomVariable { enum VarType { HOST = 0; @@ -528,7 +554,7 @@ enum CheckType { CheckPassive = 1; } -/*io::neb, neb::de_pb_host_check*/ +/* io::neb, neb::de_pb_host_check, 14 */ message HostCheck { BBDOHeader header = 1; @@ -539,7 +565,7 @@ message HostCheck { uint64 next_check = 6; } -/*io::neb, neb::de_pb_service_check*/ +/* io::neb, neb::de_pb_service_check, 15 */ message ServiceCheck { BBDOHeader header = 1; @@ -551,7 +577,7 @@ message ServiceCheck { uint64 service_id = 7; } -/*io::neb, neb::de_pb_log_entry*/ +/* io::neb, neb::de_pb_log_entry, 16 */ message LogEntry { enum LogType { SOFT = 0; @@ -589,7 +615,7 @@ message LogEntry { int32 retry = 13; } -/*io::neb, neb::de_pb_instance_status*/ +/* io::neb, neb::de_pb_instance_status, 17 */ message InstanceStatus { BBDOHeader header = 1; @@ -611,7 +637,7 @@ message InstanceStatus { uint64 instance_id = 17; } -/*io::neb, neb::de_pb_instance*/ +/* io::neb, neb::de_pb_instance, 18 */ message Instance { BBDOHeader header = 1; @@ -625,7 +651,7 @@ message Instance { string version = 9; } -/*io::neb, neb::de_pb_responsive_instance*/ +/* io::neb, neb::de_pb_responsive_instance, 19 */ message ResponsiveInstance { BBDOHeader header = 1; @@ -633,7 +659,7 @@ message ResponsiveInstance { bool responsive = 3; } -/*io::neb, neb::de_pb_acknowledgement*/ +/* io::neb, neb::de_pb_acknowledgement, 20 */ message Acknowledgement { uint64 host_id = 1; uint64 service_id = 2; @@ -653,7 +679,7 @@ message Acknowledgement { uint32 state = 12; } -/*io::neb, neb::de_pb_host_dependency*/ +/* io::neb, neb::de_pb_host_dependency, 21 */ message HostDependency { BBDOHeader header = 1; @@ -666,7 +692,7 @@ message HostDependency { string notification_failure_options = 8; } -/*io::neb, neb::de_pb_service_dependency*/ +/* io::neb, neb::de_pb_service_dependency, 22 */ message ServiceDependency { BBDOHeader header = 1; @@ -681,7 +707,7 @@ message ServiceDependency { uint64 service_id = 10; } -/*io::neb, neb::de_pb_host_group*/ +/* io::neb, neb::de_pb_host_group, 23 */ message HostGroup { BBDOHeader header = 1; @@ -691,7 +717,7 @@ message HostGroup { uint64 poller_id = 5; } -/*io::neb, neb::de_pb_service_group*/ +/* io::neb, neb::de_pb_service_group, 24 */ message ServiceGroup { BBDOHeader header = 1; @@ -701,7 +727,7 @@ message ServiceGroup { uint64 poller_id = 5; } -/*io::neb, neb::de_pb_host_group_member*/ +/* io::neb, neb::de_pb_host_group_member, 25 */ message HostGroupMember { BBDOHeader header = 1; @@ -712,7 +738,7 @@ message HostGroupMember { uint64 poller_id = 6; } -/*io::neb, neb::de_pb_service_group_member*/ +/* io::neb, neb::de_pb_service_group_member, 26 */ message ServiceGroupMember { BBDOHeader header = 1; @@ -724,7 +750,7 @@ message ServiceGroupMember { uint64 service_id = 7; } -/*io::neb, neb::de_pb_host_parent*/ +/* io::neb, neb::de_pb_host_parent, 27 */ message HostParent { BBDOHeader header = 1; @@ -733,7 +759,7 @@ message HostParent { uint64 parent_id = 4; } -/*io::neb, neb::de_pb_instance_configuration*/ +/* io::neb, neb::de_pb_instance_configuration, 28 */ message InstanceConfiguration { BBDOHeader header = 1; bool loaded = 2; @@ -755,7 +781,7 @@ message InstanceConfiguration { * relations between resources of our poller and this severity. And only if the * severity is no more used at all, we can remove it. */ -/*io::neb, neb::de_pb_severity*/ +/* io::neb, neb::de_pb_severity, 29 */ message Severity { uint64 id = 1; enum Action { @@ -796,7 +822,7 @@ enum TagType { HOSTCATEGORY = 3; } -/*io::neb, neb::de_pb_tag*/ +/* io::neb, neb::de_pb_tag, 30 */ message Tag { uint64 id = 1; enum Action { @@ -810,7 +836,7 @@ message Tag { string name = 4; int64 poller_id = 5; } - +/* Ignore */ message TagInfo { uint64 id = 1; TagType type = 2; diff --git a/bbdo/rebuild_message.proto b/bbdo/rebuild_message.proto index afc1e410747..7717833bcf2 100644 --- a/bbdo/rebuild_message.proto +++ b/bbdo/rebuild_message.proto @@ -1,13 +1,13 @@ syntax = "proto3"; package com.centreon.broker; - +/* Ignore */ message Point { int64 ctime = 1; double value = 2; uint32 status = 3; } - +/* Ignore */ message Timeserie { repeated Point pts = 1; int32 data_source_type = 2; @@ -15,7 +15,7 @@ message Timeserie { uint32 rrd_retention = 4; } -/*io::storage, storage::de_rebuild_message*/ +/* io::storage, storage::de_rebuild_message, 2 */ message RebuildMessage { enum State { START = 0; diff --git a/bbdo/remove_graph_message.proto b/bbdo/remove_graph_message.proto index 8c35c876890..0b0ef5538a6 100644 --- a/bbdo/remove_graph_message.proto +++ b/bbdo/remove_graph_message.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package com.centreon.broker; -/*io::storage, storage::de_remove_graph_message*/ +/* io::storage, storage::de_remove_graph_message, 4 */ message RemoveGraphMessage { repeated uint64 index_ids = 1; repeated uint64 metric_ids = 2; diff --git a/bbdo/storage.proto b/bbdo/storage.proto index a0544da87bd..0be01e3b349 100644 --- a/bbdo/storage.proto +++ b/bbdo/storage.proto @@ -20,7 +20,7 @@ syntax = "proto3"; package com.centreon.broker; -/*io::storage, storage::de_pb_metric*/ +/* io::storage, storage::de_pb_metric, 44 */ message Metric { enum ValueType { GAUGE = 0; @@ -40,7 +40,7 @@ message Metric { uint64 service_id = 12; } -/*io::storage, storage::de_pb_status*/ +/* io::storage, storage::de_pb_status, 45 */ message Status { uint64 index_id = 1; uint32 interval = 2; @@ -51,14 +51,14 @@ message Status { uint64 service_id = 7; } -/*io::storage, storage::de_pb_index_mapping*/ +/* io::storage, storage::de_pb_index_mapping, 46 */ message IndexMapping { uint64 index_id = 1; uint64 host_id = 2; uint64 service_id = 3; } -/*io::storage, storage::de_pb_metric_mapping*/ +/* io::storage, storage::de_pb_metric_mapping, 47 */ message MetricMapping { uint64 index_id = 1; uint64 metric_id = 2; diff --git a/broker/bam/inc/com/centreon/broker/bam/bool_service.hh b/broker/bam/inc/com/centreon/broker/bam/bool_service.hh index 03d3c13053b..b39e936131e 100644 --- a/broker/bam/inc/com/centreon/broker/bam/bool_service.hh +++ b/broker/bam/inc/com/centreon/broker/bam/bool_service.hh @@ -21,8 +21,6 @@ #include "com/centreon/broker/bam/bool_value.hh" #include "com/centreon/broker/bam/service_listener.hh" -#include "com/centreon/broker/io/stream.hh" -#include "com/centreon/broker/neb/internal.hh" namespace com::centreon::broker::bam { /** @@ -56,6 +54,9 @@ class bool_service : public bool_value, public service_listener { io::stream* visitor = nullptr) override; void service_update(const std::shared_ptr& status, io::stream* visitor = nullptr) override; + void service_update( + const std::shared_ptr& status, + io::stream* visitor = nullptr) override; void service_update(const std::shared_ptr& status, io::stream* visitor = nullptr) override; double value_hard() const override; diff --git a/broker/bam/inc/com/centreon/broker/bam/service_book.hh b/broker/bam/inc/com/centreon/broker/bam/service_book.hh index 5e9b7dfecb3..469698b5bac 100644 --- a/broker/bam/inc/com/centreon/broker/bam/service_book.hh +++ b/broker/bam/inc/com/centreon/broker/bam/service_book.hh @@ -78,6 +78,8 @@ class service_book { io::stream* visitor = nullptr); void update(const std::shared_ptr& t, io::stream* visitor = nullptr); + void update(const std::shared_ptr& t, + io::stream* visitor = nullptr); void save_to_cache(persistent_cache& cache) const; void apply_services_state(const ServicesBookState& state); }; diff --git a/broker/bam/inc/com/centreon/broker/bam/service_listener.hh b/broker/bam/inc/com/centreon/broker/bam/service_listener.hh index 5534f23ef54..449aa22050d 100644 --- a/broker/bam/inc/com/centreon/broker/bam/service_listener.hh +++ b/broker/bam/inc/com/centreon/broker/bam/service_listener.hh @@ -19,7 +19,6 @@ #ifndef CCB_BAM_SERVICE_LISTENER_HH #define CCB_BAM_SERVICE_LISTENER_HH -#include "com/centreon/broker/io/stream.hh" #include "com/centreon/broker/neb/internal.hh" namespace com::centreon::broker { @@ -51,6 +50,9 @@ class service_listener { virtual void service_update(const service_state& s); virtual void service_update(std::shared_ptr const& status, io::stream* visitor = nullptr); + virtual void service_update( + std::shared_ptr const& status, + io::stream* visitor = nullptr); virtual void service_update( std::shared_ptr const& status, io::stream* visitor = nullptr); diff --git a/broker/bam/src/bool_service.cc b/broker/bam/src/bool_service.cc index 13f4bae0c72..1a06d86acdd 100644 --- a/broker/bam/src/bool_service.cc +++ b/broker/bam/src/bool_service.cc @@ -167,6 +167,33 @@ void bool_service::service_update( } } +/** + * @brief Notify of a service status update (usually used for downtimes). + * + * @param status The adaptive status of the service. + * @param visitor The visitor to handle events. + */ +void bool_service::service_update( + const std::shared_ptr& status, + io::stream* visitor) { + auto& o = status->obj(); + if (o.has_scheduled_downtime_depth()) { + SPDLOG_LOGGER_TRACE(_logger, + "bool_service: service ({},{}) updated with " + "neb::pb_adaptive_service_status downtime: {}", + o.host_id(), o.service_id(), + o.scheduled_downtime_depth()); + if (o.host_id() == _host_id && o.service_id() == _service_id) { + bool new_in_downtime = o.scheduled_downtime_depth() > 0; + if (_in_downtime != new_in_downtime) { + _in_downtime = new_in_downtime; + _logger->trace("bool_service: updated with downtime: {}", _in_downtime); + notify_parents_of_change(visitor); + } + } + } +} + /** * Get the hard value. * diff --git a/broker/bam/src/connector.cc b/broker/bam/src/connector.cc index 0819f341921..24165c0cd07 100644 --- a/broker/bam/src/connector.cc +++ b/broker/bam/src/connector.cc @@ -35,20 +35,28 @@ #include "com/centreon/broker/neb/acknowledgement.hh" #include "com/centreon/broker/neb/downtime.hh" #include "com/centreon/broker/neb/service.hh" -#include "com/centreon/broker/neb/service_status.hh" using namespace com::centreon::broker; using namespace com::centreon::broker::bam; static constexpr multiplexing::muxer_filter _monitoring_stream_filter = { - neb::service_status::static_type(), neb::pb_service_status::static_type(), - neb::service::static_type(), neb::pb_service::static_type(), - neb::acknowledgement::static_type(), neb::pb_acknowledgement::static_type(), - neb::downtime::static_type(), neb::pb_downtime::static_type(), - bam::ba_status::static_type(), bam::pb_ba_status::static_type(), - bam::kpi_status::static_type(), bam::pb_kpi_status::static_type(), - inherited_downtime::static_type(), pb_inherited_downtime::static_type(), - extcmd::pb_ba_info::static_type(), pb_services_book_state::static_type()}; + neb::service_status::static_type(), + neb::pb_service_status::static_type(), + neb::service::static_type(), + neb::pb_service::static_type(), + neb::acknowledgement::static_type(), + neb::pb_acknowledgement::static_type(), + neb::downtime::static_type(), + neb::pb_downtime::static_type(), + neb::pb_adaptive_service_status::static_type(), + bam::ba_status::static_type(), + bam::pb_ba_status::static_type(), + bam::kpi_status::static_type(), + bam::pb_kpi_status::static_type(), + inherited_downtime::static_type(), + pb_inherited_downtime::static_type(), + extcmd::pb_ba_info::static_type(), + pb_services_book_state::static_type()}; static constexpr multiplexing::muxer_filter _monitoring_forbidden_filter = multiplexing::muxer_filter(_monitoring_stream_filter).reverse(); diff --git a/broker/bam/src/monitoring_stream.cc b/broker/bam/src/monitoring_stream.cc index 4d83c740251..1b7d8b0cf53 100644 --- a/broker/bam/src/monitoring_stream.cc +++ b/broker/bam/src/monitoring_stream.cc @@ -23,23 +23,15 @@ #include "bbdo/bam/ba_status.hh" #include "bbdo/bam/kpi_status.hh" #include "bbdo/bam/rebuild.hh" -#include "bbdo/events.hh" #include "com/centreon/broker/bam/configuration/reader_v2.hh" -#include "com/centreon/broker/bam/configuration/state.hh" #include "com/centreon/broker/bam/event_cache_visitor.hh" #include "com/centreon/broker/config/applier/state.hh" #include "com/centreon/broker/exceptions/shutdown.hh" -#include "com/centreon/broker/io/events.hh" #include "com/centreon/broker/misc/fifo_client.hh" -#include "com/centreon/broker/multiplexing/publisher.hh" #include "com/centreon/broker/neb/acknowledgement.hh" #include "com/centreon/broker/neb/downtime.hh" -#include "com/centreon/broker/neb/internal.hh" #include "com/centreon/broker/neb/service.hh" -#include "com/centreon/broker/neb/service_status.hh" -#include "com/centreon/broker/timestamp.hh" #include "com/centreon/common/pool.hh" -#include "com/centreon/exceptions/msg_fmt.hh" #include "common/log_v2/log_v2.hh" using namespace com::centreon::exceptions; @@ -410,6 +402,18 @@ int monitoring_stream::write(const std::shared_ptr& data) { _applier.book_service().update(ss, &ev_cache); ev_cache.commit_to(pblshr); } break; + case neb::pb_adaptive_service_status::static_type(): { + auto ss = std::static_pointer_cast(data); + auto& o = ss->obj(); + SPDLOG_LOGGER_TRACE(_logger, + "BAM: processing pb adaptive service status (host: " + "{}, service: {})", + o.host_id(), o.service_id()); + multiplexing::publisher pblshr; + event_cache_visitor ev_cache; + _applier.book_service().update(ss, &ev_cache); + ev_cache.commit_to(pblshr); + } break; case neb::pb_service::static_type(): { auto s = std::static_pointer_cast(data); auto& o = s->obj(); diff --git a/broker/bam/src/reporting_stream.cc b/broker/bam/src/reporting_stream.cc index e159484af9e..7f478546b80 100644 --- a/broker/bam/src/reporting_stream.cc +++ b/broker/bam/src/reporting_stream.cc @@ -1113,7 +1113,7 @@ void reporting_stream::_process_pb_ba_event( id_start ba_key = std::make_pair(be.ba_id(), be.start_time()); // event exists? if (_ba_event_cache.find(ba_key) != _ba_event_cache.end()) { - if (be.end_time() <= 0) + if (static_cast(be.end_time()) <= 0) _ba_event_update.bind_null_u64(0); else _ba_event_update.bind_value_as_u64(0, be.end_time()); @@ -1135,7 +1135,7 @@ void reporting_stream::_process_pb_ba_event( _ba_full_event_insert.bind_value_as_i32(1, be.first_level()); _ba_full_event_insert.bind_value_as_u64(2, be.start_time()); - if (be.end_time() <= 0) + if (static_cast(be.end_time()) <= 0) _ba_full_event_insert.bind_null_i64(3); else _ba_full_event_insert.bind_value_as_i64(3, be.end_time()); diff --git a/broker/bam/src/service_book.cc b/broker/bam/src/service_book.cc index f80f5c927a4..c737fafd9d4 100644 --- a/broker/bam/src/service_book.cc +++ b/broker/bam/src/service_book.cc @@ -160,6 +160,25 @@ void service_book::update(const std::shared_ptr& t, l->service_update(t, visitor); } +/** + * @brief Propagate events of type neb::service_status to the concerned services + * and then to the corresponding kpi. + * + * @param t The event to handle. + * @param visitor The stream to write into. + */ +void service_book::update( + const std::shared_ptr& t, + io::stream* visitor) { + auto obj = t->obj(); + auto found = _book.find(std::make_pair(obj.host_id(), obj.service_id())); + if (found == _book.end()) + return; + + for (auto l : found->second.listeners) + l->service_update(t, visitor); +} + /** * @brief Propagate events of type pb_service to the * concerned services and then to the corresponding kpi. diff --git a/broker/bam/src/service_listener.cc b/broker/bam/src/service_listener.cc index 61f60b9564f..89dd1407d5a 100644 --- a/broker/bam/src/service_listener.cc +++ b/broker/bam/src/service_listener.cc @@ -59,6 +59,16 @@ void service_listener::service_update( const std::shared_ptr& status [[maybe_unused]], io::stream* visitor [[maybe_unused]]) {} +/** + * @brief Notify of a service status update (usually used for downtimes). + * + * @param [[maybe_unused]] + * @param [[maybe_unused]] + */ +void service_listener::service_update( + const std::shared_ptr& status + [[maybe_unused]], + io::stream* visitor [[maybe_unused]]) {} /** * Notify of a protobuf acknowledgement. * diff --git a/broker/core/inc/com/centreon/broker/config/parser.hh b/broker/core/inc/com/centreon/broker/config/parser.hh index e6bbb93bd2a..c40f2f4eb03 100644 --- a/broker/core/inc/com/centreon/broker/config/parser.hh +++ b/broker/core/inc/com/centreon/broker/config/parser.hh @@ -21,7 +21,6 @@ #include -#include #include "com/centreon/broker/config/state.hh" #include "com/centreon/exceptions/msg_fmt.hh" diff --git a/broker/core/inc/com/centreon/broker/config/state.hh b/broker/core/inc/com/centreon/broker/config/state.hh index 2b724d2459e..9165f4229e6 100644 --- a/broker/core/inc/com/centreon/broker/config/state.hh +++ b/broker/core/inc/com/centreon/broker/config/state.hh @@ -19,7 +19,6 @@ #ifndef CCB_CONFIG_STATE_HH #define CCB_CONFIG_STATE_HH -#include #include "bbdo/bbdo/bbdo_version.hh" #include "com/centreon/broker/config/endpoint.hh" diff --git a/broker/core/sql/inc/com/centreon/broker/sql/mysql_connection.hh b/broker/core/sql/inc/com/centreon/broker/sql/mysql_connection.hh index efe6140ab21..6dd4b5147c9 100644 --- a/broker/core/sql/inc/com/centreon/broker/sql/mysql_connection.hh +++ b/broker/core/sql/inc/com/centreon/broker/sql/mysql_connection.hh @@ -19,7 +19,6 @@ #ifndef CCB_MYSQL_CONNECTION_HH #define CCB_MYSQL_CONNECTION_HH -#include "com/centreon/broker/config/applier/state.hh" #include "com/centreon/broker/sql/database_config.hh" #include "com/centreon/broker/sql/mysql_bulk_stmt.hh" #include "com/centreon/broker/sql/mysql_error.hh" diff --git a/broker/grpc/generate_proto.py b/broker/grpc/generate_proto.py index d681e223b9a..4c158efcf60 100755 --- a/broker/grpc/generate_proto.py +++ b/broker/grpc/generate_proto.py @@ -21,6 +21,7 @@ from os.path import isfile, join import re import argparse +import sys file_begin_content = """syntax = "proto3"; @@ -32,7 +33,6 @@ message CentreonEvent { oneof content { bytes buffer = 1; - """ cc_file_begin_content = """/** @@ -177,50 +177,89 @@ class received_protobuf : public io::protobuf { args = parser.parse_args() message_parser = r'^message\s+(\w+)\s+\{' -io_protobuf_parser = r'\/\*\s*(\w+::\w+\s*,\s*\w+::\w+)\s*\*\/' +io_protobuf_parser = r'\/\*\s*(\w+::\w+\s*,\s*\w+::\w+)\s*,\s*(\d+)\s*\*\/' +ignore_message = "/* Ignore */" one_of_index = 2 +message_save = [] for directory in args.proto_directory: proto_files = [f for f in listdir( directory) if f[-6:] == ".proto" and isfile(join(directory, f))] for file in proto_files: + line_counter = 0 + flag_ignore = False with open(join(directory, file)) as proto_file: messages = [] io_protobuf_match = None for line in proto_file.readlines(): + line_counter += 1 m = re.match(message_parser, line) - if m is not None and io_protobuf_match is not None: - messages.append([m.group(1), io_protobuf_match.group(1)]) + if m and io_protobuf_match: + # Check that the message and the io_protobuf_match are coherent + # Let's take the message name and remove the de_pb_ prefix if it exists + message_name = io_protobuf_match.group(1).split(',')[ + 1].split('::')[1] + message_name = message_name[3:] if message_name.startswith( + 'de_') else message_name + message_name = message_name[3:] if message_name.startswith( + 'pb_') else message_name + # Let's change the name into SnakeCase + message_name = ''.join(word.title() + for word in message_name.split('_')) + if m.group(1) != message_name: + print( + f"generate_proto.py : Error: Message {{ {m.group(1)} }} does not match the io_protobuf_match {{ {io_protobuf_match[1]} }} : file :{file}:{line_counter}", file=sys.stderr) + exit(2) + messages.append( + [m.group(1), io_protobuf_match.group(1), io_protobuf_match.group(2)]) io_protobuf_match = None + flag_ignore = True else: io_protobuf_match = re.match(io_protobuf_parser, line) - if len(messages) > 0: - file_begin_content += f"import \"{file}\";\n" - for mess, id in messages: - # proto file - file_message_centreon_event += f" {mess} {mess}_ = {one_of_index};\n" - one_of_index += 1 - lower_mess = mess.lower() - # cc file - cc_file_protobuf_to_event_function += f""" case ::stream::CentreonEvent::k{mess}: - return std::make_shared>( - stream_content, &grpc_event_type::{lower_mess}_, - &grpc_event_type::mutable_{lower_mess}_); + # check if no bbo message have the comment: Ignore + if ignore_message in line: + flag_ignore = True + # check if message has comment ignore or it's bbdo message + if flag_ignore and m: + flag_ignore = False + elif not flag_ignore and m: + print( + f"generate_proto.py : Error: Message {{ {m.group(1)} }} has no protobuf id or missing the comment /* Ignore */ : file :{file}:{line_counter}", file=sys.stderr) + print( + f"Error Add /* Ignore */ or a protobuf id as example: /*io::bam, bam::de_pb_services_book_state*/", file=sys.stderr) + exit(1) + + if len(messages) > 0: + file_begin_content += f"import \"{file}\";\n" + message_save += messages +# sort the message with index (io_protobuf_match.group(2)) +message_save.sort(key=lambda x: int(x[2])) +for mess, id, index in message_save: + # proto file + file_message_centreon_event += f" {mess} {mess}_ = {index};\n" + # count index : needed for opentelemetry + one_of_index += 1 + lower_mess = mess.lower() + # cc file + cc_file_protobuf_to_event_function += f""" case ::stream::CentreonEvent::k{mess}: +return std::make_shared>( + stream_content, &grpc_event_type::{lower_mess}_, + &grpc_event_type::mutable_{lower_mess}_); """ - cc_file_create_event_with_data_function += f""" case make_type({id}): - ret = std::make_shared( - event, reinterpret_cast( - &grpc_event_type::release_{lower_mess}_)); - ret->grpc_event.set_allocated_{lower_mess}_(&std::static_pointer_cast>(event)->mut_obj()); - break; + cc_file_create_event_with_data_function += f""" case make_type({id}): + ret = std::make_shared( + event, reinterpret_cast( + &grpc_event_type::release_{lower_mess}_)); + ret->grpc_event.set_allocated_{lower_mess}_(&std::static_pointer_cast>(event)->mut_obj()); + break; """ -#The following message is not in bbdo protobuff files so we need to add manually. - +# The following message is not in bbdo protobuff files so we need to add manually. + file_message_centreon_event += f" opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceRequest ExportMetricsServiceRequest_ = {one_of_index};\n" cc_file_protobuf_to_event_function += """ diff --git a/broker/lua/inc/com/centreon/broker/lua/macro_cache.hh b/broker/lua/inc/com/centreon/broker/lua/macro_cache.hh index d9f04f48fe2..1b3f64ba22c 100644 --- a/broker/lua/inc/com/centreon/broker/lua/macro_cache.hh +++ b/broker/lua/inc/com/centreon/broker/lua/macro_cache.hh @@ -27,7 +27,6 @@ #include "com/centreon/broker/neb/host_group.hh" #include "com/centreon/broker/neb/host_group_member.hh" #include "com/centreon/broker/neb/instance.hh" -#include "com/centreon/broker/neb/internal.hh" #include "com/centreon/broker/neb/service.hh" #include "com/centreon/broker/neb/service_group.hh" #include "com/centreon/broker/neb/service_group_member.hh" @@ -42,7 +41,7 @@ namespace com::centreon::broker::lua { class macro_cache { std::shared_ptr _cache; absl::flat_hash_map> _instances; - absl::flat_hash_map> _hosts; + absl::flat_hash_map> _hosts; /* The host groups cache stores also a set with the pollers telling they need * the cache. So if no more poller needs a host group, we can remove it from * the cache. */ @@ -54,7 +53,8 @@ class macro_cache { _host_group_members; absl::flat_hash_map, std::shared_ptr> _custom_vars; - absl::flat_hash_map, std::shared_ptr> + absl::flat_hash_map, + std::shared_ptr> _services; /* The service groups cache stores also a set with the pollers telling they * need the cache. So if no more poller needs a service group, we can remove @@ -89,8 +89,8 @@ class macro_cache { const storage::pb_index_mapping& get_index_mapping(uint64_t index_id) const; const std::shared_ptr& get_metric_mapping( uint64_t metric_id) const; - const std::shared_ptr& get_host(uint64_t host_id) const; - const std::shared_ptr& get_service(uint64_t host_id, + const std::shared_ptr& get_host(uint64_t host_id) const; + const std::shared_ptr& get_service(uint64_t host_id, uint64_t service_id) const; const std::string& get_host_name(uint64_t host_id) const; const std::string& get_notes_url(uint64_t host_id, uint64_t service_id) const; @@ -129,6 +129,7 @@ class macro_cache { void _process_host(std::shared_ptr const& data); void _process_pb_host(std::shared_ptr const& data); void _process_pb_host_status(std::shared_ptr const& data); + void _process_pb_adaptive_host_status(const std::shared_ptr& data); void _process_pb_adaptive_host(std::shared_ptr const& data); void _process_host_group(std::shared_ptr const& data); void _process_pb_host_group(std::shared_ptr const& data); @@ -138,7 +139,9 @@ class macro_cache { void _process_pb_custom_variable(std::shared_ptr const& data); void _process_service(std::shared_ptr const& data); void _process_pb_service(std::shared_ptr const& data); - void _process_pb_service_status(std::shared_ptr const& data); + void _process_pb_service_status(const std::shared_ptr& data); + void _process_pb_adaptive_service_status( + const std::shared_ptr& data); void _process_pb_adaptive_service(std::shared_ptr const& data); void _process_service_group(std::shared_ptr const& data); void _process_pb_service_group(std::shared_ptr const& data); diff --git a/broker/lua/src/macro_cache.cc b/broker/lua/src/macro_cache.cc index d043a51c218..ceafc912a6e 100644 --- a/broker/lua/src/macro_cache.cc +++ b/broker/lua/src/macro_cache.cc @@ -18,14 +18,12 @@ #include "com/centreon/broker/lua/macro_cache.hh" #include -#include +#include #include "bbdo/bam/dimension_ba_bv_relation_event.hh" #include "bbdo/bam/dimension_ba_event.hh" #include "bbdo/bam/dimension_bv_event.hh" #include "bbdo/storage/index_mapping.hh" #include "bbdo/storage/metric_mapping.hh" -#include "com/centreon/broker/neb/internal.hh" -#include "com/centreon/exceptions/msg_fmt.hh" #include "common/log_v2/log_v2.hh" using namespace com::centreon::exceptions; @@ -101,7 +99,7 @@ macro_cache::get_metric_mapping(uint64_t metric_id) const { * * @return A shared pointer on the service. */ -const std::shared_ptr& macro_cache::get_service( +const std::shared_ptr& macro_cache::get_service( uint64_t host_id, uint64_t service_id) const { auto found = _services.find({host_id, service_id}); @@ -119,7 +117,8 @@ const std::shared_ptr& macro_cache::get_service( * * @return A shared pointer on the host. */ -const std::shared_ptr& macro_cache::get_host(uint64_t host_id) const { +const std::shared_ptr& macro_cache::get_host( + uint64_t host_id) const { auto found = _hosts.find(host_id); if (found == _hosts.end()) @@ -141,13 +140,7 @@ std::string const& macro_cache::get_host_name(uint64_t host_id) const { if (found == _hosts.end()) throw msg_fmt("lua: could not find information on host {}", host_id); - if (found->second->type() == neb::host::static_type()) { - auto const& s = std::static_pointer_cast(found->second); - return s->host_name; - } else { - auto const& s = std::static_pointer_cast(found->second); - return s->obj().name(); - } + return found->second->obj().name(); } /** @@ -210,13 +203,8 @@ std::string_view macro_cache::get_check_command(uint64_t host_id, "lua: could not find the check command of the service (host_id: {}, " "service_id: {})", host_id, service_id); - if (found->second->type() == neb::service::static_type()) { - neb::service& s = static_cast(*found->second); - retval = s.check_command; - } else { - neb::pb_service& s = static_cast(*found->second); - retval = s.obj().check_command(); - } + neb::pb_service& s = static_cast(*found->second); + retval = s.obj().check_command(); } /* Case of hosts */ else { @@ -225,13 +213,8 @@ std::string_view macro_cache::get_check_command(uint64_t host_id, throw msg_fmt( "lua: could not find the check command of the host (host_id: {})", host_id); - if (found->second->type() == neb::host::static_type()) { - neb::host& s = static_cast(*found->second); - retval = s.check_command; - } else { - neb::pb_host& s = static_cast(*found->second); - retval = s.obj().check_command(); - } + neb::pb_host& s = static_cast(*found->second); + retval = s.obj().check_command(); } return retval; } @@ -252,26 +235,14 @@ std::string const& macro_cache::get_notes_url(uint64_t host_id, if (found == _services.end()) throw msg_fmt("lua: could not find information on service ({}, {})", host_id, service_id); - if (found->second->type() == neb::service::static_type()) { - auto const& s = std::static_pointer_cast(found->second); - return s->notes_url; - } else { - auto const& s = std::static_pointer_cast(found->second); - return s->obj().notes_url(); - } + return found->second->obj().notes_url(); } else { auto found = _hosts.find(host_id); if (found == _hosts.end()) throw msg_fmt("lua: could not find information on host {}", host_id); - if (found->second->type() == neb::host::static_type()) { - auto const& s = std::static_pointer_cast(found->second); - return s->notes_url; - } else { - auto const& s = std::static_pointer_cast(found->second); - return s->obj().notes_url(); - } + return found->second->obj().notes_url(); } } @@ -291,26 +262,14 @@ std::string const& macro_cache::get_action_url(uint64_t host_id, if (found == _services.end()) throw msg_fmt("lua: could not find information on service ({}, {})", host_id, service_id); - if (found->second->type() == neb::service::static_type()) { - auto const& s = std::static_pointer_cast(found->second); - return s->action_url; - } else { - auto const& s = std::static_pointer_cast(found->second); - return s->obj().action_url(); - } + return found->second->obj().action_url(); } else { auto found = _hosts.find(host_id); if (found == _hosts.end()) throw msg_fmt("lua: could not find information on host {}", host_id); - if (found->second->type() == neb::host::static_type()) { - auto const& s = std::static_pointer_cast(found->second); - return s->action_url; - } else { - auto const& s = std::static_pointer_cast(found->second); - return s->obj().action_url(); - } + return found->second->obj().action_url(); } } @@ -330,26 +289,13 @@ std::string const& macro_cache::get_notes(uint64_t host_id, if (found == _services.end()) throw msg_fmt("lua: cound not find information on service ({}, {})", host_id, service_id); - if (found->second->type() == neb::service::static_type()) { - auto const& s = std::static_pointer_cast(found->second); - return s->notes; - } else { - auto const& s = std::static_pointer_cast(found->second); - return s->obj().notes(); - } + return found->second->obj().notes(); } else { auto found = _hosts.find(host_id); if (found == _hosts.end()) throw msg_fmt("lua: could not find information on host {}", host_id); - - if (found->second->type() == neb::host::static_type()) { - auto const& s = std::static_pointer_cast(found->second); - return s->notes; - } else { - auto const& s = std::static_pointer_cast(found->second); - return s->obj().notes(); - } + return found->second->obj().notes(); } } @@ -396,13 +342,7 @@ std::string const& macro_cache::get_service_description( if (found == _services.end()) throw msg_fmt("lua: could not find information on service ({}, {})", host_id, service_id); - if (found->second->type() == neb::service::static_type()) { - auto const& s = std::static_pointer_cast(found->second); - return s->service_description; - } else { - auto const& s = std::static_pointer_cast(found->second); - return s->obj().description(); - } + return found->second->obj().description(); } /** @@ -529,6 +469,9 @@ void macro_cache::write(std::shared_ptr const& data) { case neb::pb_adaptive_host::static_type(): _process_pb_adaptive_host(data); break; + case neb::pb_adaptive_host_status::static_type(): + _process_pb_adaptive_host_status(data); + break; case neb::host_group::static_type(): _process_host_group(data); break; @@ -550,6 +493,9 @@ void macro_cache::write(std::shared_ptr const& data) { case neb::pb_service_status::static_type(): _process_pb_service_status(data); break; + case neb::pb_adaptive_service_status::static_type(): + _process_pb_adaptive_service_status(data); + break; case neb::pb_adaptive_service::static_type(): _process_pb_adaptive_service(data); break; @@ -632,14 +578,105 @@ void macro_cache::_process_pb_instance(std::shared_ptr const& data) { * * @param h The event. */ -void macro_cache::_process_host(std::shared_ptr const& data) { - std::shared_ptr const& h = +void macro_cache::_process_host(const std::shared_ptr& data) { + const std::shared_ptr& h = std::static_pointer_cast(data); SPDLOG_LOGGER_DEBUG(_cache->logger(), "lua: processing host '{}' of id {}", h->host_name, h->host_id); - if (h->enabled) - _hosts[h->host_id] = data; - else + if (h->enabled) { + auto found = _hosts.find(h->host_id); + if (found == _hosts.end()) { + auto new_host = std::make_shared(); + _hosts[h->host_id] = new_host; + found = _hosts.find(h->host_id); + } + Host& current_host = + std::static_pointer_cast(found->second)->mut_obj(); + current_host.set_host_id(h->host_id); + current_host.set_acknowledged(h->acknowledged); + current_host.set_acknowledgement_type( + static_cast(h->acknowledgement_type)); + current_host.set_active_checks(h->active_checks_enabled); + current_host.set_enabled(h->enabled); + current_host.set_scheduled_downtime_depth(h->downtime_depth); + current_host.set_check_command(h->check_command); + current_host.set_check_interval(h->check_interval); + current_host.set_check_period(h->check_period); + current_host.set_check_type(static_cast(h->check_type)); + current_host.set_check_attempt(h->current_check_attempt); + current_host.set_state(static_cast(h->current_state)); + current_host.set_event_handler_enabled(h->event_handler_enabled); + current_host.set_event_handler(h->event_handler); + current_host.set_execution_time(h->execution_time); + current_host.set_flap_detection(h->default_flap_detection_enabled); + current_host.set_checked(h->has_been_checked); + current_host.set_flapping(h->is_flapping); + current_host.set_last_check(h->last_check); + current_host.set_last_hard_state( + static_cast(h->last_hard_state)); + current_host.set_last_hard_state_change(h->last_hard_state_change); + current_host.set_last_notification(h->last_notification); + current_host.set_notification_number(h->notification_number); + current_host.set_last_state_change(h->last_state_change); + current_host.set_last_time_down(h->last_time_down); + current_host.set_last_time_unreachable(h->last_time_unreachable); + current_host.set_last_time_up(h->last_time_up); + current_host.set_last_update(h->last_update); + current_host.set_latency(h->latency); + current_host.set_max_check_attempts(h->max_check_attempts); + current_host.set_next_check(h->next_check); + current_host.set_next_host_notification(h->next_notification); + current_host.set_no_more_notifications(h->no_more_notifications); + current_host.set_notify(h->notifications_enabled); + current_host.set_output(h->output); + current_host.set_passive_checks(h->passive_checks_enabled); + current_host.set_percent_state_change(h->percent_state_change); + current_host.set_perfdata(h->perf_data); + current_host.set_retry_interval(h->retry_interval); + current_host.set_should_be_scheduled(h->should_be_scheduled); + current_host.set_obsess_over_host(h->obsess_over); + current_host.set_state_type(static_cast(h->state_type)); + current_host.set_action_url(h->action_url); + current_host.set_address(h->address); + current_host.set_alias(h->alias); + current_host.set_check_freshness(h->check_freshness); + current_host.set_default_active_checks(h->default_active_checks_enabled); + current_host.set_default_event_handler_enabled( + h->default_event_handler_enabled); + current_host.set_default_flap_detection(h->default_flap_detection_enabled); + current_host.set_default_notify(h->default_notifications_enabled); + current_host.set_default_passive_checks(h->default_passive_checks_enabled); + current_host.set_display_name(h->display_name); + current_host.set_first_notification_delay(h->first_notification_delay); + current_host.set_flap_detection_on_down(h->flap_detection_on_down); + current_host.set_flap_detection_on_unreachable( + h->flap_detection_on_unreachable); + current_host.set_flap_detection_on_up(h->flap_detection_on_up); + current_host.set_freshness_threshold(h->freshness_threshold); + current_host.set_high_flap_threshold(h->high_flap_threshold); + current_host.set_low_flap_threshold(h->low_flap_threshold); + current_host.set_name(h->host_name); + current_host.set_icon_image(h->icon_image); + current_host.set_icon_image_alt(h->icon_image_alt); + current_host.set_instance_id(h->poller_id); + current_host.set_notes(h->notes); + current_host.set_notes_url(h->notes_url); + current_host.set_notification_interval(h->notification_interval); + current_host.set_notification_period(h->notification_period); + current_host.set_notify_on_down(h->notify_on_down); + current_host.set_notify_on_downtime(h->notify_on_downtime); + current_host.set_notify_on_flapping(h->notify_on_flapping); + current_host.set_notify_on_recovery(h->notify_on_recovery); + current_host.set_notify_on_unreachable(h->notify_on_unreachable); + current_host.set_stalk_on_down(h->stalk_on_down); + current_host.set_stalk_on_unreachable(h->stalk_on_unreachable); + current_host.set_stalk_on_up(h->stalk_on_up); + current_host.set_statusmap_image(h->statusmap_image); + current_host.set_retain_nonstatus_information( + h->retain_nonstatus_information); + current_host.set_retain_status_information(h->retain_status_information); + current_host.set_timezone(h->timezone); + } else _hosts.erase(h->host_id); } @@ -649,12 +686,11 @@ void macro_cache::_process_host(std::shared_ptr const& data) { * @param h The event. */ void macro_cache::_process_pb_host(std::shared_ptr const& data) { - std::shared_ptr const& h = - std::static_pointer_cast(data); + const auto& h = std::static_pointer_cast(data); SPDLOG_LOGGER_DEBUG(_cache->logger(), "lua: processing host '{}' of id {}", h->obj().name(), h->obj().host_id()); if (h->obj().enabled()) - _hosts[h->obj().host_id()] = data; + _hosts[h->obj().host_id()] = h; else _hosts.erase(h->obj().host_id()); } @@ -676,67 +712,67 @@ void macro_cache::_process_pb_host_status( return; } - if (it->second->type() == make_type(io::neb, neb::de_host)) { - auto& hst = *std::static_pointer_cast(it->second); - hst.has_been_checked = obj.checked(); - hst.check_type = obj.check_type(); - hst.current_state = obj.state(); - hst.state_type = obj.state_type(); - hst.last_state_change = obj.last_state_change(); - hst.last_hard_state = obj.last_hard_state(); - hst.last_hard_state_change = obj.last_hard_state_change(); - hst.last_time_up = obj.last_time_up(); - hst.last_time_down = obj.last_time_down(); - hst.last_time_unreachable = obj.last_time_unreachable(); - hst.output = obj.output(); - hst.perf_data = obj.perfdata(); - hst.is_flapping = obj.flapping(); - hst.percent_state_change = obj.percent_state_change(); - hst.latency = obj.latency(); - hst.execution_time = obj.execution_time(); - hst.last_check = obj.last_check(); - hst.next_check = obj.next_check(); - hst.should_be_scheduled = obj.should_be_scheduled(); - hst.current_check_attempt = obj.check_attempt(); - hst.notification_number = obj.notification_number(); - hst.no_more_notifications = obj.no_more_notifications(); - hst.last_notification = obj.last_notification(); - hst.next_notification = obj.next_host_notification(); - hst.acknowledgement_type = obj.acknowledgement_type(); - hst.downtime_depth = obj.scheduled_downtime_depth(); - } else if (it->second->type() == make_type(io::neb, neb::de_pb_host)) { - auto& hst = std::static_pointer_cast(it->second)->mut_obj(); - hst.set_checked(obj.checked()); - hst.set_check_type(static_cast(obj.check_type())); - hst.set_state(static_cast(obj.state())); - hst.set_state_type(static_cast(obj.state_type())); - hst.set_last_state_change(obj.last_state_change()); - hst.set_last_hard_state(static_cast(obj.last_hard_state())); - hst.set_last_hard_state_change(obj.last_hard_state_change()); - hst.set_last_time_up(obj.last_time_up()); - hst.set_last_time_down(obj.last_time_down()); - hst.set_last_time_unreachable(obj.last_time_unreachable()); - hst.set_output(obj.output()); - hst.set_perfdata(obj.perfdata()); - hst.set_flapping(obj.flapping()); - hst.set_percent_state_change(obj.percent_state_change()); - hst.set_latency(obj.latency()); - hst.set_execution_time(obj.execution_time()); - hst.set_last_check(obj.last_check()); - hst.set_next_check(obj.next_check()); - hst.set_should_be_scheduled(obj.should_be_scheduled()); - hst.set_check_attempt(obj.check_attempt()); - hst.set_notification_number(obj.notification_number()); - hst.set_no_more_notifications(obj.no_more_notifications()); - hst.set_last_notification(obj.last_notification()); - hst.set_next_host_notification(obj.next_host_notification()); - hst.set_acknowledgement_type(obj.acknowledgement_type()); - hst.set_scheduled_downtime_depth(obj.scheduled_downtime_depth()); - } else { - _cache->logger()->error("lua: The host ({}) stored in cache is corrupted", - obj.host_id()); + auto& hst = std::static_pointer_cast(it->second)->mut_obj(); + hst.set_checked(obj.checked()); + hst.set_check_type(static_cast(obj.check_type())); + hst.set_state(static_cast(obj.state())); + hst.set_state_type(static_cast(obj.state_type())); + hst.set_last_state_change(obj.last_state_change()); + hst.set_last_hard_state(static_cast(obj.last_hard_state())); + hst.set_last_hard_state_change(obj.last_hard_state_change()); + hst.set_last_time_up(obj.last_time_up()); + hst.set_last_time_down(obj.last_time_down()); + hst.set_last_time_unreachable(obj.last_time_unreachable()); + hst.set_output(obj.output()); + hst.set_perfdata(obj.perfdata()); + hst.set_flapping(obj.flapping()); + hst.set_percent_state_change(obj.percent_state_change()); + hst.set_latency(obj.latency()); + hst.set_execution_time(obj.execution_time()); + hst.set_last_check(obj.last_check()); + hst.set_next_check(obj.next_check()); + hst.set_should_be_scheduled(obj.should_be_scheduled()); + hst.set_check_attempt(obj.check_attempt()); + hst.set_notification_number(obj.notification_number()); + hst.set_no_more_notifications(obj.no_more_notifications()); + hst.set_last_notification(obj.last_notification()); + hst.set_next_host_notification(obj.next_host_notification()); + hst.set_acknowledgement_type(obj.acknowledgement_type()); + hst.set_scheduled_downtime_depth(obj.scheduled_downtime_depth()); +} + +/** + * @brief Process a pb adaptive host event. + * + * @param data An AdaptiveHostStatus event. + */ +void macro_cache::_process_pb_adaptive_host_status( + const std::shared_ptr& data) { + const auto& s = std::static_pointer_cast(data); + const auto& obj = s->obj(); + + SPDLOG_LOGGER_DEBUG(_cache->logger(), + "lua: processing adaptive host status ({})", + obj.host_id()); + + auto it = _hosts.find(obj.host_id()); + if (it == _hosts.end()) { + _cache->logger()->warn( + "lua: Attempt to update host ({}) in lua cache, but it does not " + "exist. Maybe Engine should be restarted to update the cache.", + obj.host_id()); + return; } + + auto& hst = std::static_pointer_cast(it->second)->mut_obj(); + if (obj.has_scheduled_downtime_depth()) + hst.set_scheduled_downtime_depth(obj.scheduled_downtime_depth()); + if (obj.has_acknowledgement_type()) + hst.set_acknowledgement_type(obj.acknowledgement_type()); + if (obj.has_notification_number()) + hst.set_notification_number(obj.notification_number()); } + /** * Process a pb adaptive host event. * @@ -750,71 +786,37 @@ void macro_cache::_process_pb_adaptive_host( auto& ah = h->obj(); auto it = _hosts.find(ah.host_id()); if (it != _hosts.end()) { - if (it->second->type() == make_type(io::neb, neb::de_host)) { - auto& h = *std::static_pointer_cast(it->second); - if (ah.has_notify()) - h.notifications_enabled = ah.notify(); - if (ah.has_active_checks()) - h.active_checks_enabled = ah.active_checks(); - if (ah.has_should_be_scheduled()) - h.should_be_scheduled = ah.should_be_scheduled(); - if (ah.has_passive_checks()) - h.passive_checks_enabled = ah.passive_checks(); - if (ah.has_event_handler_enabled()) - h.event_handler_enabled = ah.event_handler_enabled(); - if (ah.has_flap_detection()) - h.flap_detection_enabled = ah.flap_detection(); - if (ah.has_obsess_over_host()) - h.obsess_over = ah.obsess_over_host(); - if (ah.has_event_handler()) - h.event_handler = ah.event_handler(); - if (ah.has_check_command()) - h.check_command = ah.check_command(); - if (ah.has_check_interval()) - h.check_interval = ah.check_interval(); - if (ah.has_retry_interval()) - h.retry_interval = ah.retry_interval(); - if (ah.has_max_check_attempts()) - h.max_check_attempts = ah.max_check_attempts(); - if (ah.has_check_freshness()) - h.check_freshness = ah.check_freshness(); - if (ah.has_check_period()) - h.check_period = ah.check_period(); - if (ah.has_notification_period()) - h.notification_period = ah.notification_period(); - } else { - auto& h = std::static_pointer_cast(it->second)->mut_obj(); - if (ah.has_notify()) - h.set_notify(ah.notify()); - if (ah.has_active_checks()) - h.set_active_checks(ah.active_checks()); - if (ah.has_should_be_scheduled()) - h.set_should_be_scheduled(ah.should_be_scheduled()); - if (ah.has_passive_checks()) - h.set_passive_checks(ah.passive_checks()); - if (ah.has_event_handler_enabled()) - h.set_event_handler_enabled(ah.event_handler_enabled()); - if (ah.has_flap_detection()) - h.set_flap_detection(ah.flap_detection()); - if (ah.has_obsess_over_host()) - h.set_obsess_over_host(ah.obsess_over_host()); - if (ah.has_event_handler()) - h.set_event_handler(ah.event_handler()); - if (ah.has_check_command()) - h.set_check_command(ah.check_command()); - if (ah.has_check_interval()) - h.set_check_interval(ah.check_interval()); - if (ah.has_retry_interval()) - h.set_retry_interval(ah.retry_interval()); - if (ah.has_max_check_attempts()) - h.set_max_check_attempts(ah.max_check_attempts()); - if (ah.has_check_freshness()) - h.set_check_freshness(ah.check_freshness()); - if (ah.has_check_period()) - h.set_check_period(ah.check_period()); - if (ah.has_notification_period()) - h.set_notification_period(ah.notification_period()); - } + auto& h = it->second->mut_obj(); + if (ah.has_notify()) + h.set_notify(ah.notify()); + if (ah.has_active_checks()) + h.set_active_checks(ah.active_checks()); + if (ah.has_should_be_scheduled()) + h.set_should_be_scheduled(ah.should_be_scheduled()); + if (ah.has_passive_checks()) + h.set_passive_checks(ah.passive_checks()); + if (ah.has_event_handler_enabled()) + h.set_event_handler_enabled(ah.event_handler_enabled()); + if (ah.has_flap_detection()) + h.set_flap_detection(ah.flap_detection()); + if (ah.has_obsess_over_host()) + h.set_obsess_over_host(ah.obsess_over_host()); + if (ah.has_event_handler()) + h.set_event_handler(ah.event_handler()); + if (ah.has_check_command()) + h.set_check_command(ah.check_command()); + if (ah.has_check_interval()) + h.set_check_interval(ah.check_interval()); + if (ah.has_retry_interval()) + h.set_retry_interval(ah.retry_interval()); + if (ah.has_max_check_attempts()) + h.set_max_check_attempts(ah.max_check_attempts()); + if (ah.has_check_freshness()) + h.set_check_freshness(ah.check_freshness()); + if (ah.has_check_period()) + h.set_check_period(ah.check_period()); + if (ah.has_notification_period()) + h.set_notification_period(ah.notification_period()); } else SPDLOG_LOGGER_WARN( _cache->logger(), @@ -958,9 +960,137 @@ void macro_cache::_process_service(std::shared_ptr const& data) { SPDLOG_LOGGER_DEBUG(_cache->logger(), "lua: processing service ({}, {}) (description:{})", s->host_id, s->service_id, s->service_description); - if (s->enabled) - _services[{s->host_id, s->service_id}] = data; - else + if (s->enabled) { + auto found = _services.find({s->host_id, s->service_id}); + if (found == _services.end()) { + auto new_service = std::make_shared(); + _services[{s->host_id, s->service_id}] = new_service; + found = _services.find({s->host_id, s->service_id}); + } + Service& current_service = + std::static_pointer_cast(found->second)->mut_obj(); + current_service.set_host_id(s->host_id); + current_service.set_service_id(s->service_id); + current_service.set_acknowledged(s->acknowledged); + current_service.set_acknowledgement_type( + static_cast(s->acknowledgement_type)); + current_service.set_active_checks(s->active_checks_enabled); + current_service.set_enabled(s->enabled); + current_service.set_scheduled_downtime_depth(s->downtime_depth); + current_service.set_check_command(s->check_command); + current_service.set_check_interval(s->check_interval); + current_service.set_check_period(s->check_period); + current_service.set_check_type( + static_cast(s->check_type)); + current_service.set_check_attempt(s->current_check_attempt); + current_service.set_state(static_cast(s->current_state)); + current_service.set_event_handler_enabled(s->event_handler_enabled); + current_service.set_event_handler(s->event_handler); + current_service.set_execution_time(s->execution_time); + current_service.set_flap_detection(s->default_flap_detection_enabled); + current_service.set_checked(s->has_been_checked); + current_service.set_flapping(s->is_flapping); + current_service.set_last_check(s->last_check); + current_service.set_last_hard_state( + static_cast(s->last_hard_state)); + current_service.set_last_hard_state_change(s->last_hard_state_change); + current_service.set_last_notification(s->last_notification); + current_service.set_notification_number(s->notification_number); + current_service.set_last_state_change(s->last_state_change); + current_service.set_last_time_ok(s->last_time_ok); + current_service.set_last_time_warning(s->last_time_warning); + current_service.set_last_time_critical(s->last_time_critical); + current_service.set_last_time_unknown(s->last_time_unknown); + current_service.set_last_update(s->last_update); + current_service.set_latency(s->latency); + current_service.set_max_check_attempts(s->max_check_attempts); + current_service.set_next_check(s->next_check); + current_service.set_next_notification(s->next_notification); + current_service.set_no_more_notifications(s->no_more_notifications); + current_service.set_notify(s->notifications_enabled); + std::string_view long_output = s->output; + std::vector output = + absl::StrSplit(long_output, absl::MaxSplits('\n', 2)); + switch (output.size()) { + case 2: + current_service.set_long_output(std::string(output[1])); + case 1: + current_service.set_output(std::string(output[0])); + break; + } + current_service.set_passive_checks(s->passive_checks_enabled); + current_service.set_percent_state_change(s->percent_state_change); + current_service.set_perfdata(s->perf_data); + current_service.set_retry_interval(s->retry_interval); + current_service.set_host_name(s->host_name); + current_service.set_description(s->service_description); + current_service.set_should_be_scheduled(s->should_be_scheduled); + current_service.set_obsess_over_service(s->obsess_over); + current_service.set_state_type( + static_cast(s->state_type)); + current_service.set_action_url(s->action_url); + current_service.set_check_freshness(s->check_freshness); + current_service.set_default_active_checks(s->default_active_checks_enabled); + current_service.set_default_event_handler_enabled( + s->default_event_handler_enabled); + current_service.set_default_flap_detection( + s->default_flap_detection_enabled); + current_service.set_default_notify(s->default_notifications_enabled); + current_service.set_default_passive_checks( + s->default_passive_checks_enabled); + current_service.set_display_name(s->display_name); + current_service.set_first_notification_delay(s->first_notification_delay); + current_service.set_flap_detection_on_critical( + s->flap_detection_on_critical); + current_service.set_flap_detection_on_ok(s->flap_detection_on_ok); + current_service.set_flap_detection_on_unknown(s->flap_detection_on_unknown); + current_service.set_flap_detection_on_warning(s->flap_detection_on_warning); + current_service.set_freshness_threshold(s->freshness_threshold); + current_service.set_high_flap_threshold(s->high_flap_threshold); + current_service.set_low_flap_threshold(s->low_flap_threshold); + current_service.set_icon_image(s->icon_image); + current_service.set_icon_image_alt(s->icon_image_alt); + current_service.set_is_volatile(s->is_volatile); + current_service.set_notes(s->notes); + current_service.set_notes_url(s->notes_url); + current_service.set_notification_interval(s->notification_interval); + current_service.set_notification_period(s->notification_period); + current_service.set_notify_on_critical(s->notify_on_critical); + current_service.set_notify_on_downtime(s->notify_on_downtime); + current_service.set_notify_on_flapping(s->notify_on_flapping); + current_service.set_notify_on_recovery(s->notify_on_recovery); + current_service.set_notify_on_unknown(s->notify_on_unknown); + current_service.set_notify_on_warning(s->notify_on_warning); + current_service.set_stalk_on_critical(s->stalk_on_critical); + current_service.set_stalk_on_ok(s->stalk_on_ok); + current_service.set_stalk_on_unknown(s->stalk_on_unknown); + current_service.set_stalk_on_warning(s->stalk_on_warning); + current_service.set_retain_nonstatus_information( + s->retain_nonstatus_information); + current_service.set_retain_status_information(s->retain_status_information); + if (std::string_view(current_service.host_name().data(), 12) == + "_Module_Meta") { + if (std::string_view(current_service.description().data(), 5) == + "meta_") { + current_service.set_type(METASERVICE); + uint64_t iid; + std::string_view id = + std::string_view(current_service.description()).substr(5); + if (absl::SimpleAtoi(id, &iid)) + current_service.set_internal_id(iid); + } + } else if (std::string_view(current_service.host_name().data(), 11) == + "_Module_BAM") { + if (std::string_view(current_service.description().data(), 3) == "ba_") { + current_service.set_type(BA); + uint64_t iid; + std::string_view id = + std::string_view(current_service.description()).substr(3); + if (absl::SimpleAtoi(id, &iid)) + current_service.set_internal_id(iid); + } + } + } else _services.erase({s->host_id, s->service_id}); } @@ -975,11 +1105,44 @@ void macro_cache::_process_pb_service(std::shared_ptr const& data) { _cache->logger(), "lua: processing service ({}, {}) (description:{})", s->obj().host_id(), s->obj().service_id(), s->obj().description()); if (s->obj().enabled()) - _services[{s->obj().host_id(), s->obj().service_id()}] = data; + _services[{s->obj().host_id(), s->obj().service_id()}] = s; else _services.erase({s->obj().host_id(), s->obj().service_id()}); } +/** + * @brief Process a pb adaptive service event. + * + * @param data An AdaptiveServiceStatus event. + */ +void macro_cache::_process_pb_adaptive_service_status( + const std::shared_ptr& data) { + const auto& s = + std::static_pointer_cast(data); + const auto& obj = s->obj(); + + SPDLOG_LOGGER_DEBUG(_cache->logger(), + "lua: processing adaptive service status ({}, {})", + obj.host_id(), obj.service_id()); + + auto it = _services.find({obj.host_id(), obj.service_id()}); + if (it == _services.end()) { + _cache->logger()->warn( + "lua: Attempt to update service ({}, {}) in lua cache, but it does not " + "exist. Maybe Engine should be restarted to update the cache.", + obj.host_id(), obj.service_id()); + return; + } + + auto& svc = std::static_pointer_cast(it->second)->mut_obj(); + if (obj.has_acknowledgement_type()) + svc.set_acknowledgement_type(obj.acknowledgement_type()); + if (obj.has_scheduled_downtime_depth()) + svc.set_scheduled_downtime_depth(obj.scheduled_downtime_depth()); + if (obj.has_notification_number()) + svc.set_notification_number(obj.notification_number()); +} + void macro_cache::_process_pb_service_status( const std::shared_ptr& data) { const auto& s = std::static_pointer_cast(data); @@ -998,70 +1161,34 @@ void macro_cache::_process_pb_service_status( return; } - if (it->second->type() == make_type(io::neb, neb::de_service)) { - auto& svc = *std::static_pointer_cast(it->second); - svc.has_been_checked = obj.checked(); - svc.check_type = obj.check_type(); - svc.current_state = obj.state(); - svc.state_type = obj.state_type(); - svc.last_state_change = obj.last_state_change(); - svc.last_hard_state = obj.last_hard_state(); - svc.last_hard_state_change = obj.last_hard_state_change(); - svc.last_time_ok = obj.last_time_ok(); - svc.last_time_warning = obj.last_time_warning(); - svc.last_time_critical = obj.last_time_critical(); - svc.last_time_unknown = obj.last_time_unknown(); - svc.output = obj.output(); - svc.perf_data = obj.perfdata(); - svc.is_flapping = obj.flapping(); - svc.percent_state_change = obj.percent_state_change(); - svc.latency = obj.latency(); - svc.execution_time = obj.execution_time(); - svc.last_check = obj.last_check(); - svc.next_check = obj.next_check(); - svc.should_be_scheduled = obj.should_be_scheduled(); - svc.current_check_attempt = obj.check_attempt(); - svc.notification_number = obj.notification_number(); - svc.no_more_notifications = obj.no_more_notifications(); - svc.last_notification = obj.last_notification(); - svc.next_notification = obj.next_notification(); - svc.acknowledgement_type = obj.acknowledgement_type(); - svc.downtime_depth = obj.scheduled_downtime_depth(); - } else if (it->second->type() == make_type(io::neb, neb::de_pb_service)) { - auto& svc = - std::static_pointer_cast(it->second)->mut_obj(); - svc.set_checked(obj.checked()); - svc.set_check_type(static_cast(obj.check_type())); - svc.set_state(static_cast(obj.state())); - svc.set_state_type(static_cast(obj.state_type())); - svc.set_last_state_change(obj.last_state_change()); - svc.set_last_hard_state(static_cast(obj.last_hard_state())); - svc.set_last_hard_state_change(obj.last_hard_state_change()); - svc.set_last_time_ok(obj.last_time_ok()); - svc.set_last_time_warning(obj.last_time_warning()); - svc.set_last_time_critical(obj.last_time_critical()); - svc.set_last_time_unknown(obj.last_time_unknown()); - svc.set_output(obj.output()); - svc.set_perfdata(obj.perfdata()); - svc.set_flapping(obj.flapping()); - svc.set_percent_state_change(obj.percent_state_change()); - svc.set_latency(obj.latency()); - svc.set_execution_time(obj.execution_time()); - svc.set_last_check(obj.last_check()); - svc.set_next_check(obj.next_check()); - svc.set_should_be_scheduled(obj.should_be_scheduled()); - svc.set_check_attempt(obj.check_attempt()); - svc.set_notification_number(obj.notification_number()); - svc.set_no_more_notifications(obj.no_more_notifications()); - svc.set_last_notification(obj.last_notification()); - svc.set_next_notification(obj.next_notification()); - svc.set_acknowledgement_type(obj.acknowledgement_type()); - svc.set_scheduled_downtime_depth(obj.scheduled_downtime_depth()); - } else { - _cache->logger()->error( - "lua: The service ({}, {}) stored in cache is corrupted", obj.host_id(), - obj.service_id()); - } + auto& svc = it->second->mut_obj(); + svc.set_checked(obj.checked()); + svc.set_check_type(static_cast(obj.check_type())); + svc.set_state(static_cast(obj.state())); + svc.set_state_type(static_cast(obj.state_type())); + svc.set_last_state_change(obj.last_state_change()); + svc.set_last_hard_state(static_cast(obj.last_hard_state())); + svc.set_last_hard_state_change(obj.last_hard_state_change()); + svc.set_last_time_ok(obj.last_time_ok()); + svc.set_last_time_warning(obj.last_time_warning()); + svc.set_last_time_critical(obj.last_time_critical()); + svc.set_last_time_unknown(obj.last_time_unknown()); + svc.set_output(obj.output()); + svc.set_perfdata(obj.perfdata()); + svc.set_flapping(obj.flapping()); + svc.set_percent_state_change(obj.percent_state_change()); + svc.set_latency(obj.latency()); + svc.set_execution_time(obj.execution_time()); + svc.set_last_check(obj.last_check()); + svc.set_next_check(obj.next_check()); + svc.set_should_be_scheduled(obj.should_be_scheduled()); + svc.set_check_attempt(obj.check_attempt()); + svc.set_notification_number(obj.notification_number()); + svc.set_no_more_notifications(obj.no_more_notifications()); + svc.set_last_notification(obj.last_notification()); + svc.set_next_notification(obj.next_notification()); + svc.set_acknowledgement_type(obj.acknowledgement_type()); + svc.set_scheduled_downtime_depth(obj.scheduled_downtime_depth()); } /** @@ -1078,72 +1205,37 @@ void macro_cache::_process_pb_adaptive_service( auto& as = s->obj(); auto it = _services.find({as.host_id(), as.service_id()}); if (it != _services.end()) { - if (it->second->type() == make_type(io::neb, neb::de_service)) { - auto& s = *std::static_pointer_cast(it->second); - if (as.has_notify()) - s.notifications_enabled = as.notify(); - if (as.has_active_checks()) - s.active_checks_enabled = as.active_checks(); - if (as.has_should_be_scheduled()) - s.should_be_scheduled = as.should_be_scheduled(); - if (as.has_passive_checks()) - s.passive_checks_enabled = as.passive_checks(); - if (as.has_event_handler_enabled()) - s.event_handler_enabled = as.event_handler_enabled(); - if (as.has_flap_detection_enabled()) - s.flap_detection_enabled = as.flap_detection_enabled(); - if (as.has_obsess_over_service()) - s.obsess_over = as.obsess_over_service(); - if (as.has_event_handler()) - s.event_handler = as.event_handler(); - if (as.has_check_command()) - s.check_command = as.check_command(); - if (as.has_check_interval()) - s.check_interval = as.check_interval(); - if (as.has_retry_interval()) - s.retry_interval = as.retry_interval(); - if (as.has_max_check_attempts()) - s.max_check_attempts = as.max_check_attempts(); - if (as.has_check_freshness()) - s.check_freshness = as.check_freshness(); - if (as.has_check_period()) - s.check_period = as.check_period(); - if (as.has_notification_period()) - s.notification_period = as.notification_period(); - } else { - auto& s = - std::static_pointer_cast(it->second)->mut_obj(); - if (as.has_notify()) - s.set_notify(as.notify()); - if (as.has_active_checks()) - s.set_active_checks(as.active_checks()); - if (as.has_should_be_scheduled()) - s.set_should_be_scheduled(as.should_be_scheduled()); - if (as.has_passive_checks()) - s.set_passive_checks(as.passive_checks()); - if (as.has_event_handler_enabled()) - s.set_event_handler_enabled(as.event_handler_enabled()); - if (as.has_flap_detection_enabled()) - s.set_flap_detection(as.flap_detection_enabled()); - if (as.has_obsess_over_service()) - s.set_obsess_over_service(as.obsess_over_service()); - if (as.has_event_handler()) - s.set_event_handler(as.event_handler()); - if (as.has_check_command()) - s.set_check_command(as.check_command()); - if (as.has_check_interval()) - s.set_check_interval(as.check_interval()); - if (as.has_retry_interval()) - s.set_retry_interval(as.retry_interval()); - if (as.has_max_check_attempts()) - s.set_max_check_attempts(as.max_check_attempts()); - if (as.has_check_freshness()) - s.set_check_freshness(as.check_freshness()); - if (as.has_check_period()) - s.set_check_period(as.check_period()); - if (as.has_notification_period()) - s.set_notification_period(as.notification_period()); - } + auto& s = it->second->mut_obj(); + if (as.has_notify()) + s.set_notify(as.notify()); + if (as.has_active_checks()) + s.set_active_checks(as.active_checks()); + if (as.has_should_be_scheduled()) + s.set_should_be_scheduled(as.should_be_scheduled()); + if (as.has_passive_checks()) + s.set_passive_checks(as.passive_checks()); + if (as.has_event_handler_enabled()) + s.set_event_handler_enabled(as.event_handler_enabled()); + if (as.has_flap_detection_enabled()) + s.set_flap_detection(as.flap_detection_enabled()); + if (as.has_obsess_over_service()) + s.set_obsess_over_service(as.obsess_over_service()); + if (as.has_event_handler()) + s.set_event_handler(as.event_handler()); + if (as.has_check_command()) + s.set_check_command(as.check_command()); + if (as.has_check_interval()) + s.set_check_interval(as.check_interval()); + if (as.has_retry_interval()) + s.set_retry_interval(as.retry_interval()); + if (as.has_max_check_attempts()) + s.set_max_check_attempts(as.max_check_attempts()); + if (as.has_check_freshness()) + s.set_check_freshness(as.check_freshness()); + if (as.has_check_period()) + s.set_check_period(as.check_period()); + if (as.has_notification_period()) + s.set_notification_period(as.notification_period()); } else { SPDLOG_LOGGER_WARN( _cache->logger(), diff --git a/broker/lua/test/lua.cc b/broker/lua/test/lua.cc index 8268c693b3e..eef66569bdf 100644 --- a/broker/lua/test/lua.cc +++ b/broker/lua/test/lua.cc @@ -17,7 +17,6 @@ */ #include -#include #include #include @@ -30,10 +29,7 @@ #include "com/centreon/broker/config/applier/init.hh" #include "com/centreon/broker/config/applier/modules.hh" #include "com/centreon/broker/lua/luabinding.hh" -#include "com/centreon/broker/lua/macro_cache.hh" -#include "com/centreon/broker/misc/variant.hh" #include "com/centreon/broker/neb/events.hh" -#include "com/centreon/broker/neb/instance.hh" #include "com/centreon/exceptions/msg_fmt.hh" #include "common/log_v2/log_v2.hh" @@ -4836,3 +4832,227 @@ TEST_F(LuaTest, WithBadFilter2) { ASSERT_FALSE(bb->has_filter()); RemoveFile(filename); } + +// When a host is stored in the cache and an AdaptiveHostStatus is written +// Then the host in cache is updated. +TEST_F(LuaTest, AdaptiveHostCacheTest) { + config::applier::modules modules(log_v2::instance().get(log_v2::LUA)); + modules.load_file("./broker/neb/10-neb.so"); + std::map conf; + std::string filename("/tmp/cache_test.lua"); + auto hst{std::make_shared()}; + hst->host_id = 1; + hst->host_name = "centreon"; + hst->check_command = "echo 'John Doe'"; + hst->alias = "alias-centreon"; + hst->address = "4.3.2.1"; + _cache->write(hst); + + auto ahoststatus = std::make_shared(); + auto& obj = ahoststatus->mut_obj(); + obj.set_host_id(1); + obj.set_scheduled_downtime_depth(2); + _cache->write(ahoststatus); + + CreateScript(filename, + "function init(conf)\n" + " broker_log:set_parameters(3, '/tmp/log')\n" + " local hst = broker_cache:get_host(1)\n" + " broker_log:info(1, 'alias ' .. hst.alias .. ' address ' .. " + "hst.address .. ' name ' .. hst.name .. ' " + "scheduled_downtime_depth ' .. hst.scheduled_downtime_depth)\n" + "end\n\n" + "function write(d)\n" + " return true\n" + "end\n"); + auto binding{std::make_unique(filename, conf, *_cache)}; + std::string lst(ReadFile("/tmp/log")); + + ASSERT_NE(lst.find("alias alias-centreon address 4.3.2.1 name centreon " + "scheduled_downtime_depth 2"), + std::string::npos); + RemoveFile(filename); + RemoveFile("/tmp/log"); +} + +// When an AdaptiveHostStatus is written +// Then only the written fields are available. +TEST_F(LuaTest, AdaptiveHostCacheFieldTest) { + config::applier::modules modules(log_v2::instance().get(log_v2::LUA)); + modules.load_file("./broker/neb/10-neb.so"); + std::map conf; + std::string filename("/tmp/cache_test.lua"); + auto hst{std::make_shared()}; + hst->host_id = 1; + hst->host_name = "centreon"; + hst->check_command = "echo 'John Doe'"; + hst->alias = "alias-centreon"; + hst->address = "4.3.2.1"; + _cache->write(hst); + + CreateScript(filename, + "broker_api_version = 2\n" + "function init(conf)\n" + " broker_log:set_parameters(3, '/tmp/log')\n" + "end\n\n" + "function write(d)\n" + " broker_log:info(1, broker.json_encode(d))\n" + " return true\n" + "end\n"); + + auto binding{std::make_unique(filename, conf, *_cache)}; + + auto ahoststatus1 = std::make_shared(); + { + auto& obj = ahoststatus1->mut_obj(); + obj.set_host_id(1); + obj.set_notification_number(9); + binding->write(ahoststatus1); + } + + auto ahoststatus2 = std::make_shared(); + { + auto& obj = ahoststatus2->mut_obj(); + obj.set_host_id(2); + obj.set_acknowledgement_type(STICKY); + binding->write(ahoststatus2); + } + + auto ahoststatus3 = std::make_shared(); + { + auto& obj = ahoststatus3->mut_obj(); + obj.set_host_id(3); + obj.set_scheduled_downtime_depth(5); + binding->write(ahoststatus3); + } + std::string lst(ReadFile("/tmp/log")); + ASSERT_NE(lst.find("{\"_type\":65592, \"category\":1, \"element\":56, " + "\"host_id\":1, \"notification_number\":9}"), + std::string::npos); + ASSERT_NE(lst.find("{\"_type\":65592, \"category\":1, \"element\":56, " + "\"host_id\":2, \"acknowledgement_type\":2}"), + std::string::npos); + ASSERT_NE(lst.find("{\"_type\":65592, \"category\":1, \"element\":56, " + "\"host_id\":3, \"scheduled_downtime_depth\":5}"), + std::string::npos); + RemoveFile(filename); + RemoveFile("/tmp/log"); +} + +// When a service is stored in the cache and an AdaptiveServiceStatus is written +// Then the service in cache is updated. +TEST_F(LuaTest, AdaptiveServiceCacheTest) { + config::applier::modules modules(log_v2::instance().get(log_v2::LUA)); + modules.load_file("./broker/neb/10-neb.so"); + std::map conf; + std::string filename("/tmp/cache_test.lua"); + auto svc{std::make_shared()}; + svc->host_id = 1; + svc->service_id = 2; + svc->host_name = "centreon-host"; + svc->service_description = "centreon-description"; + svc->check_command = "echo 'John Doe'"; + svc->display_name = "alias-centreon"; + _cache->write(svc); + + auto aservicestatus = std::make_shared(); + auto& obj = aservicestatus->mut_obj(); + obj.set_host_id(1); + obj.set_service_id(2); + obj.set_scheduled_downtime_depth(3); + _cache->write(aservicestatus); + + CreateScript(filename, + "function init(conf)\n" + " broker_log:set_parameters(3, '/tmp/log')\n" + " local svc = broker_cache:get_service(1, 2)\n" + " broker_log:info(1, 'display_name ' .. svc.display_name .. ' " + "description ' .. " + "svc.description .. ' check command ' .. svc.check_command .. ' " + "scheduled_downtime_depth ' .. svc.scheduled_downtime_depth)\n" + "end\n\n" + "function write(d)\n" + " return true\n" + "end\n"); + auto binding{std::make_unique(filename, conf, *_cache)}; + std::string lst(ReadFile("/tmp/log")); + + ASSERT_NE( + lst.find("display_name alias-centreon description centreon-description " + "check command echo 'John Doe' scheduled_downtime_depth 3"), + std::string::npos); + RemoveFile(filename); + // RemoveFile("/tmp/log"); +} + +// When an AdaptiveHostStatus is written +// Then only the written fields are available. +TEST_F(LuaTest, AdaptiveServiceCacheFieldTest) { + config::applier::modules modules(log_v2::instance().get(log_v2::LUA)); + modules.load_file("./broker/neb/10-neb.so"); + std::map conf; + std::string filename("/tmp/cache_test.lua"); + auto svc{std::make_shared()}; + svc->host_id = 1; + svc->service_id = 2; + svc->host_name = "centreon-host"; + svc->service_description = "centreon-description"; + svc->check_command = "echo 'John Doe'"; + svc->display_name = "alias-centreon"; + _cache->write(svc); + + CreateScript(filename, + "broker_api_version = 2\n" + "function init(conf)\n" + " broker_log:set_parameters(3, '/tmp/log')\n" + "end\n\n" + "function write(d)\n" + " broker_log:info(1, broker.json_encode(d))\n" + " return true\n" + "end\n"); + + auto binding{std::make_unique(filename, conf, *_cache)}; + + auto aservicestatus1 = std::make_shared(); + { + auto& obj = aservicestatus1->mut_obj(); + obj.set_host_id(1); + obj.set_service_id(2); + obj.set_notification_number(9); + binding->write(aservicestatus1); + } + + auto aservicestatus2 = std::make_shared(); + { + auto& obj = aservicestatus2->mut_obj(); + obj.set_host_id(1); + obj.set_service_id(2); + obj.set_acknowledgement_type(STICKY); + binding->write(aservicestatus2); + } + + auto aservicestatus3 = std::make_shared(); + { + auto& obj = aservicestatus3->mut_obj(); + obj.set_host_id(1); + obj.set_service_id(3); + obj.set_scheduled_downtime_depth(5); + binding->write(aservicestatus3); + } + std::string lst(ReadFile("/tmp/log")); + std::cout << lst << std::endl; + ASSERT_NE(lst.find("{\"_type\":65591, \"category\":1, \"element\":55, " + "\"host_id\":1, \"service_id\":2, \"type\":0, " + "\"internal_id\":0, \"notification_number\":9}"), + std::string::npos); + ASSERT_NE(lst.find("{\"_type\":65591, \"category\":1, \"element\":55, " + "\"host_id\":1, \"service_id\":2, \"type\":0, " + "\"internal_id\":0, \"acknowledgement_type\":2}"), + std::string::npos); + ASSERT_NE(lst.find("{\"_type\":65591, \"category\":1, \"element\":55, " + "\"host_id\":1, \"service_id\":3, \"type\":0, " + "\"internal_id\":0, \"scheduled_downtime_depth\":5}"), + std::string::npos); + RemoveFile(filename); + // RemoveFile("/tmp/log"); +} diff --git a/broker/neb/inc/com/centreon/broker/neb/comment.hh b/broker/neb/inc/com/centreon/broker/neb/comment.hh index e50b7219146..4633d6786e2 100644 --- a/broker/neb/inc/com/centreon/broker/neb/comment.hh +++ b/broker/neb/inc/com/centreon/broker/neb/comment.hh @@ -19,12 +19,9 @@ #ifndef CCB_NEB_COMMENT_HH #define CCB_NEB_COMMENT_HH -#include "com/centreon/broker/io/data.hh" -#include "com/centreon/broker/io/event_info.hh" #include "com/centreon/broker/io/events.hh" #include "com/centreon/broker/mapping/entry.hh" #include "com/centreon/broker/neb/internal.hh" -#include "com/centreon/broker/timestamp.hh" namespace com::centreon::broker { @@ -68,6 +65,6 @@ class comment : public io::data { }; } // namespace neb -} +} // namespace com::centreon::broker #endif // !CCB_NEB_COMMENT_HH diff --git a/broker/neb/inc/com/centreon/broker/neb/custom_variable_status.hh b/broker/neb/inc/com/centreon/broker/neb/custom_variable_status.hh index c4dd57843c6..75c7428aab3 100644 --- a/broker/neb/inc/com/centreon/broker/neb/custom_variable_status.hh +++ b/broker/neb/inc/com/centreon/broker/neb/custom_variable_status.hh @@ -19,12 +19,9 @@ #ifndef CCB_NEB_CUSTOM_VARIABLE_STATUS_HH #define CCB_NEB_CUSTOM_VARIABLE_STATUS_HH -#include "com/centreon/broker/io/data.hh" -#include "com/centreon/broker/io/event_info.hh" #include "com/centreon/broker/io/events.hh" #include "com/centreon/broker/mapping/entry.hh" #include "com/centreon/broker/neb/internal.hh" -#include "com/centreon/broker/timestamp.hh" namespace com::centreon::broker { @@ -62,6 +59,6 @@ class custom_variable_status : public io::data { }; } // namespace neb -} +} // namespace com::centreon::broker #endif // !CCB_NEB_CUSTOM_VARIABLE_STATUS_HH diff --git a/broker/neb/inc/com/centreon/broker/neb/downtime.hh b/broker/neb/inc/com/centreon/broker/neb/downtime.hh index 64c50828565..1deed00962f 100644 --- a/broker/neb/inc/com/centreon/broker/neb/downtime.hh +++ b/broker/neb/inc/com/centreon/broker/neb/downtime.hh @@ -19,12 +19,9 @@ #ifndef CCB_NEB_DOWNTIME_HH #define CCB_NEB_DOWNTIME_HH -#include "com/centreon/broker/io/data.hh" -#include "com/centreon/broker/io/event_info.hh" #include "com/centreon/broker/io/events.hh" #include "com/centreon/broker/mapping/entry.hh" #include "com/centreon/broker/neb/internal.hh" -#include "com/centreon/broker/timestamp.hh" namespace com::centreon::broker { @@ -85,6 +82,6 @@ class downtime : public io::data { }; } // namespace neb -} +} // namespace com::centreon::broker #endif // !CCB_NEB_DOWNTIME_HH diff --git a/broker/neb/inc/com/centreon/broker/neb/host.hh b/broker/neb/inc/com/centreon/broker/neb/host.hh index 6b328e42a86..c8c2180a4e9 100644 --- a/broker/neb/inc/com/centreon/broker/neb/host.hh +++ b/broker/neb/inc/com/centreon/broker/neb/host.hh @@ -1,20 +1,20 @@ -/* -** Copyright 2009-2013,2015 Centreon -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -** -** For more information : contact@centreon.com -*/ +/** + * Copyright 2009-2013,2015 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ #ifndef CCB_NEB_HOST_HH #define CCB_NEB_HOST_HH @@ -72,6 +72,6 @@ class host : public host_service, public host_status { }; } // namespace neb -} +} // namespace com::centreon::broker #endif // !CCB_NEB_HOST_HH diff --git a/broker/neb/inc/com/centreon/broker/neb/host_check.hh b/broker/neb/inc/com/centreon/broker/neb/host_check.hh index 29cc98f2225..3f75d131d65 100644 --- a/broker/neb/inc/com/centreon/broker/neb/host_check.hh +++ b/broker/neb/inc/com/centreon/broker/neb/host_check.hh @@ -19,11 +19,8 @@ #ifndef CCB_NEB_HOST_CHECK_HH #define CCB_NEB_HOST_CHECK_HH -#include "com/centreon/broker/io/event_info.hh" -#include "com/centreon/broker/io/events.hh" #include "com/centreon/broker/mapping/entry.hh" #include "com/centreon/broker/neb/check.hh" -#include "com/centreon/broker/neb/internal.hh" namespace com::centreon::broker { diff --git a/broker/neb/inc/com/centreon/broker/neb/instance_configuration.hh b/broker/neb/inc/com/centreon/broker/neb/instance_configuration.hh index 8e311835ea2..b3ee87151a1 100644 --- a/broker/neb/inc/com/centreon/broker/neb/instance_configuration.hh +++ b/broker/neb/inc/com/centreon/broker/neb/instance_configuration.hh @@ -19,12 +19,9 @@ #ifndef CCB_NEB_INSTANCE_CONFIGURATION_HH #define CCB_NEB_INSTANCE_CONFIGURATION_HH -#include "com/centreon/broker/io/data.hh" -#include "com/centreon/broker/io/event_info.hh" #include "com/centreon/broker/io/events.hh" #include "com/centreon/broker/mapping/entry.hh" #include "com/centreon/broker/neb/internal.hh" -#include "com/centreon/broker/timestamp.hh" namespace com::centreon::broker { @@ -59,6 +56,6 @@ class instance_configuration : public io::data { }; } // namespace neb -} +} // namespace com::centreon::broker #endif // !CCB_NEB_INSTANCE_CONFIGURATION_HH diff --git a/broker/neb/inc/com/centreon/broker/neb/instance_status.hh b/broker/neb/inc/com/centreon/broker/neb/instance_status.hh index d5fdb19ed19..badf7b9ffaa 100644 --- a/broker/neb/inc/com/centreon/broker/neb/instance_status.hh +++ b/broker/neb/inc/com/centreon/broker/neb/instance_status.hh @@ -24,7 +24,6 @@ #include "com/centreon/broker/mapping/entry.hh" #include "com/centreon/broker/neb/internal.hh" #include "com/centreon/broker/neb/status.hh" -#include "com/centreon/broker/timestamp.hh" namespace com::centreon::broker { @@ -70,6 +69,6 @@ class instance_status : public status { }; } // namespace neb -} +} // namespace com::centreon::broker #endif // !CCB_EVENTS_INSTANCE_STATUS_HH diff --git a/broker/neb/inc/com/centreon/broker/neb/internal.hh b/broker/neb/inc/com/centreon/broker/neb/internal.hh index c12f0b660d3..be3ea2e973e 100644 --- a/broker/neb/inc/com/centreon/broker/neb/internal.hh +++ b/broker/neb/inc/com/centreon/broker/neb/internal.hh @@ -47,6 +47,9 @@ using pb_downtime = using pb_host_status = io::protobuf; +using pb_adaptive_host_status = + io::protobuf; using pb_host = io::protobuf; using pb_adaptive_host = io::protobuf; @@ -60,6 +63,10 @@ using pb_adaptive_service = using pb_service_status = io::protobuf; +using pb_adaptive_service_status = + io::protobuf; + using pb_severity = io::protobuf; diff --git a/broker/neb/inc/com/centreon/broker/neb/service_check.hh b/broker/neb/inc/com/centreon/broker/neb/service_check.hh index 97474467007..2278c93c1dd 100644 --- a/broker/neb/inc/com/centreon/broker/neb/service_check.hh +++ b/broker/neb/inc/com/centreon/broker/neb/service_check.hh @@ -19,11 +19,8 @@ #ifndef CCB_NEB_SERVICE_CHECK_HH #define CCB_NEB_SERVICE_CHECK_HH -#include "com/centreon/broker/io/event_info.hh" -#include "com/centreon/broker/io/events.hh" #include "com/centreon/broker/mapping/entry.hh" #include "com/centreon/broker/neb/check.hh" -#include "com/centreon/broker/neb/internal.hh" namespace com::centreon::broker { diff --git a/broker/neb/inc/com/centreon/broker/neb/service_status.hh b/broker/neb/inc/com/centreon/broker/neb/service_status.hh index c486e1b66a3..a2d635f5a34 100644 --- a/broker/neb/inc/com/centreon/broker/neb/service_status.hh +++ b/broker/neb/inc/com/centreon/broker/neb/service_status.hh @@ -24,7 +24,6 @@ #include "com/centreon/broker/mapping/entry.hh" #include "com/centreon/broker/neb/host_service_status.hh" #include "com/centreon/broker/neb/internal.hh" -#include "com/centreon/broker/timestamp.hh" namespace com::centreon::broker { @@ -62,6 +61,6 @@ class service_status : public host_service_status { }; } // namespace neb -} +} // namespace com::centreon::broker #endif // !CCB_NEB_SERVICE_STATUS_HH diff --git a/broker/neb/inc/com/centreon/broker/neb/set_log_data.hh b/broker/neb/inc/com/centreon/broker/neb/set_log_data.hh index 9e1dc851477..038a202e279 100644 --- a/broker/neb/inc/com/centreon/broker/neb/set_log_data.hh +++ b/broker/neb/inc/com/centreon/broker/neb/set_log_data.hh @@ -21,7 +21,6 @@ #include "com/centreon/broker/neb/log_entry.hh" #include "com/centreon/engine/host.hh" -#include "com/centreon/engine/service.hh" namespace com { namespace centreon { diff --git a/broker/neb/inc/com/centreon/logging/backend.hh b/broker/neb/inc/com/centreon/logging/backend.hh deleted file mode 100644 index 066458d723f..00000000000 --- a/broker/neb/inc/com/centreon/logging/backend.hh +++ /dev/null @@ -1,81 +0,0 @@ -/* -** Copyright 2011-2013 Centreon -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -** -** For more information : contact@centreon.com -*/ - -#ifndef CC_LOGGING_BACKEND_HH -#define CC_LOGGING_BACKEND_HH - - -namespace com::centreon { - -namespace misc { -class stringifier; -} - -namespace logging { -enum time_precision { none = 0, microsecond = 1, millisecond = 2, second = 3 }; - -/** - * @class backend backend.hh "com/centreon/logging/backend.hh" - * @brief Base logging backend class. - * - * This class defines an interface to create logger backend, to - * log data into many different objects. - */ -class backend { - public: - backend(bool is_sync = true, - bool show_pid = true, - time_precision show_timestamp = second, - bool show_thread_id = false); - backend(backend const& right); - virtual ~backend() noexcept; - backend& operator=(backend const& right); - virtual void close() noexcept = 0; - virtual bool enable_sync() const; - virtual void enable_sync(bool enable); - virtual void log(uint64_t types, uint32_t verbose, char const* msg) noexcept; - virtual void log(uint64_t types, - uint32_t verbose, - char const* msg, - uint32_t size) noexcept = 0; - virtual void open() = 0; - virtual void reopen() = 0; - virtual bool show_pid() const; - virtual void show_pid(bool enable); - virtual time_precision show_timestamp() const; - virtual void show_timestamp(time_precision val); - virtual bool show_thread_id() const; - virtual void show_thread_id(bool enable); - - protected: - void _build_header(misc::stringifier& buffer); - - bool _is_sync; - mutable std::recursive_mutex _lock; - bool _show_pid; - time_precision _show_timestamp; - bool _show_thread_id; - - protected: - void _internal_copy(backend const& right); -}; -} // namespace logging - -} - -#endif // !CC_LOGGING_BACKEND_HH diff --git a/broker/neb/precomp_inc/precomp.hpp b/broker/neb/precomp_inc/precomp.hpp index 0c373302776..83f32a05ff3 100644 --- a/broker/neb/precomp_inc/precomp.hpp +++ b/broker/neb/precomp_inc/precomp.hpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include diff --git a/broker/neb/src/broker.cc b/broker/neb/src/broker.cc index 3a7c8e2f291..c69613aacc8 100644 --- a/broker/neb/src/broker.cc +++ b/broker/neb/src/broker.cc @@ -152,6 +152,10 @@ void broker_module_init(void const* arg) { e.register_event(make_type(io::neb, neb::de_pb_service_status), "ServiceStatus", &neb::pb_service_status::operations, "services"); + e.register_event(make_type(io::neb, neb::de_pb_adaptive_service_status), + "AdaptiveServiceStatus", + &neb::pb_adaptive_service_status::operations, + "services"); e.register_event(make_type(io::neb, neb::de_pb_host), "Host", &neb::pb_host::operations, "hosts"); @@ -161,6 +165,10 @@ void broker_module_init(void const* arg) { e.register_event(make_type(io::neb, neb::de_pb_host_status), "HostStatus", &neb::pb_host_status::operations, "hosts"); + e.register_event(make_type(io::neb, neb::de_pb_adaptive_host_status), + "AdaptiveHostStatus", + &neb::pb_adaptive_host_status::operations, + "hosts"); e.register_event(make_type(io::neb, neb::de_pb_severity), "Severity", &neb::pb_severity::operations, "severities"); diff --git a/broker/neb/src/callbacks.cc b/broker/neb/src/callbacks.cc index 243e31b106f..a40071ceaa2 100644 --- a/broker/neb/src/callbacks.cc +++ b/broker/neb/src/callbacks.cc @@ -18,36 +18,24 @@ #include "com/centreon/broker/neb/callbacks.hh" +#include #include #include -#include "bbdo/neb.pb.h" -#include "opentelemetry/proto/collector/metrics/v1/metrics_service.pb.h" - #include "com/centreon/broker/bbdo/internal.hh" #include "com/centreon/broker/config/applier/state.hh" #include "com/centreon/broker/config/parser.hh" -#include "com/centreon/broker/config/state.hh" -#include "com/centreon/broker/neb/callback.hh" #include "com/centreon/broker/neb/events.hh" #include "com/centreon/broker/neb/initial.hh" -#include "com/centreon/broker/neb/internal.hh" #include "com/centreon/broker/neb/set_log_data.hh" #include "com/centreon/common/time.hh" #include "com/centreon/common/utf8.hh" #include "com/centreon/engine/anomalydetection.hh" #include "com/centreon/engine/broker.hh" -#include "com/centreon/engine/comment.hh" #include "com/centreon/engine/events/loop.hh" #include "com/centreon/engine/globals.hh" -#include "com/centreon/engine/hostgroup.hh" -#include "com/centreon/engine/nebcallbacks.hh" #include "com/centreon/engine/nebstructs.hh" -#include "com/centreon/engine/servicegroup.hh" #include "com/centreon/engine/severity.hh" -#include "com/centreon/engine/tag.hh" -#include "com/centreon/exceptions/msg_fmt.hh" -#include "common/log_v2/log_v2.hh" using namespace com::centreon::broker; using namespace com::centreon::exceptions; @@ -1094,7 +1082,7 @@ int neb::callback_group(int callback_type, void* data) { new_hg->poller_id = config::applier::state::instance().poller_id(); new_hg->id = host_group->get_id(); new_hg->enabled = group_data->type == NEBTYPE_HOSTGROUP_ADD || - (group_data->type == NEBTYPE_ADAPTIVEHOST_UPDATE && + (group_data->type == NEBTYPE_HOSTGROUP_UPDATE && !host_group->members.empty()); new_hg->name = common::check_string_utf8(host_group->get_group_name()); @@ -1992,10 +1980,9 @@ int neb::callback_pb_host_check(int callback_type, void* data) { * * @return 0 on success. */ -int neb::callback_host_status(int callback_type, void* data) { +int neb::callback_host_status(int callback_type [[maybe_unused]], void* data) { // Log message. SPDLOG_LOGGER_DEBUG(neb_logger, "callbacks: generating host status event"); - (void)callback_type; try { // In/Out variables. @@ -2121,90 +2108,115 @@ int neb::callback_host_status(int callback_type, void* data) { * * @return 0 on success. */ -int neb::callback_pb_host_status(int callback_type, void* data) noexcept { +int neb::callback_pb_host_status(int callback_type [[maybe_unused]], + void* data) noexcept { // Log message. SPDLOG_LOGGER_DEBUG( neb_logger, "callbacks: generating pb host status check result event protobuf"); - (void)callback_type; - const engine::host* eh{static_cast( - static_cast(data)->object_ptr)}; + nebstruct_host_status_data* hsd = + static_cast(data); + const engine::host* eh = static_cast(hsd->object_ptr); - auto h{std::make_shared()}; - HostStatus& hscr = h.get()->mut_obj(); + auto handle_acknowledgement = [](uint16_t state, auto& hscr) { + auto it = gl_acknowledgements.find(std::make_pair(hscr.host_id(), 0u)); + if (it != gl_acknowledgements.end() && + hscr.acknowledgement_type() == AckType::NONE) { + if (it->second->type() == make_type(io::neb, de_pb_acknowledgement)) { + neb_logger->debug("acknowledgement found on host {}", hscr.host_id()); + neb::pb_acknowledgement* a = + static_cast(it->second.get()); + if (!(!state // !(OK or (normal ack and NOK)) + || (!a->obj().sticky() && state != a->obj().state()))) { + a->mut_obj().set_deletion_time(time(nullptr)); + gl_publisher.write(std::move(it->second)); + } + } else { + neb::acknowledgement* a = + static_cast(it->second.get()); + if (!(!state // !(OK or (normal ack and NOK)) + || (!a->is_sticky && state != a->state))) { + a->deletion_time = time(nullptr); + gl_publisher.write(std::move(it->second)); + } + } + gl_acknowledgements.erase(it); + } + }; - hscr.set_host_id(eh->host_id()); - if (hscr.host_id() == 0) - SPDLOG_LOGGER_ERROR(neb_logger, "could not find ID of host '{}'", - eh->name()); + uint16_t state = + eh->has_been_checked() ? eh->get_current_state() : 4; // Pending state. + + if (hsd->attributes != engine::host::STATUS_ALL) { + auto h{std::make_shared()}; + AdaptiveHostStatus& hst = h.get()->mut_obj(); + if (hsd->attributes & engine::host::STATUS_DOWNTIME_DEPTH) { + hst.set_host_id(eh->host_id()); + hst.set_scheduled_downtime_depth(eh->get_scheduled_downtime_depth()); + } + if (hsd->attributes & engine::host::STATUS_NOTIFICATION_NUMBER) { + hst.set_host_id(eh->host_id()); + hst.set_notification_number(eh->get_notification_number()); + } + if (hsd->attributes & engine::host::STATUS_ACKNOWLEDGEMENT) { + hst.set_host_id(eh->host_id()); + hst.set_acknowledgement_type(eh->get_acknowledgement()); + } + gl_publisher.write(h); + + // Acknowledgement event. + handle_acknowledgement(state, hst); + } else { + auto h{std::make_shared()}; + HostStatus& hscr = h.get()->mut_obj(); + + hscr.set_host_id(eh->host_id()); + if (hscr.host_id() == 0) + SPDLOG_LOGGER_ERROR(neb_logger, "could not find ID of host '{}'", + eh->name()); - if (eh->problem_has_been_acknowledged()) hscr.set_acknowledgement_type(eh->get_acknowledgement()); - else - hscr.set_acknowledgement_type(AckType::NONE); - - hscr.set_check_type(static_cast(eh->get_check_type())); - hscr.set_check_attempt(eh->get_current_attempt()); - hscr.set_state(static_cast( - eh->has_been_checked() ? eh->get_current_state() : 4)); // Pending state. - hscr.set_execution_time(eh->get_execution_time()); - hscr.set_checked(eh->has_been_checked()); - hscr.set_flapping(eh->get_is_flapping()); - hscr.set_last_check(eh->get_last_check()); - hscr.set_last_hard_state( - static_cast(eh->get_last_hard_state())); - hscr.set_last_hard_state_change(eh->get_last_hard_state_change()); - hscr.set_last_notification(eh->get_last_notification()); - hscr.set_notification_number(eh->get_notification_number()); - hscr.set_last_state_change(eh->get_last_state_change()); - hscr.set_last_time_down(eh->get_last_time_down()); - hscr.set_last_time_unreachable(eh->get_last_time_unreachable()); - hscr.set_last_time_up(eh->get_last_time_up()); - hscr.set_latency(eh->get_latency()); - hscr.set_next_check(eh->get_next_check()); - hscr.set_next_host_notification(eh->get_next_notification()); - hscr.set_no_more_notifications(eh->get_no_more_notifications()); - if (!eh->get_plugin_output().empty()) - hscr.set_output(common::check_string_utf8(eh->get_plugin_output())); - if (!eh->get_long_plugin_output().empty()) - hscr.set_output(common::check_string_utf8(eh->get_long_plugin_output())); - - hscr.set_percent_state_change(eh->get_percent_state_change()); - if (!eh->get_perf_data().empty()) - hscr.set_perfdata(common::check_string_utf8(eh->get_perf_data())); - hscr.set_should_be_scheduled(eh->get_should_be_scheduled()); - hscr.set_state_type(static_cast( - eh->has_been_checked() ? eh->get_state_type() : engine::notifier::hard)); - hscr.set_scheduled_downtime_depth(eh->get_scheduled_downtime_depth()); + hscr.set_check_type( + static_cast(eh->get_check_type())); + hscr.set_check_attempt(eh->get_current_attempt()); + hscr.set_state(static_cast(state)); + hscr.set_execution_time(eh->get_execution_time()); + hscr.set_checked(eh->has_been_checked()); + hscr.set_flapping(eh->get_is_flapping()); + hscr.set_last_check(eh->get_last_check()); + hscr.set_last_hard_state( + static_cast(eh->get_last_hard_state())); + hscr.set_last_hard_state_change(eh->get_last_hard_state_change()); + hscr.set_last_notification(eh->get_last_notification()); + hscr.set_notification_number(eh->get_notification_number()); + hscr.set_last_state_change(eh->get_last_state_change()); + hscr.set_last_time_down(eh->get_last_time_down()); + hscr.set_last_time_unreachable(eh->get_last_time_unreachable()); + hscr.set_last_time_up(eh->get_last_time_up()); + hscr.set_latency(eh->get_latency()); + hscr.set_next_check(eh->get_next_check()); + hscr.set_next_host_notification(eh->get_next_notification()); + hscr.set_no_more_notifications(eh->get_no_more_notifications()); + if (!eh->get_plugin_output().empty()) + hscr.set_output(common::check_string_utf8(eh->get_plugin_output())); + if (!eh->get_long_plugin_output().empty()) + hscr.set_output(common::check_string_utf8(eh->get_long_plugin_output())); - // Send event(s). - gl_publisher.write(h); + hscr.set_percent_state_change(eh->get_percent_state_change()); + if (!eh->get_perf_data().empty()) + hscr.set_perfdata(common::check_string_utf8(eh->get_perf_data())); + hscr.set_should_be_scheduled(eh->get_should_be_scheduled()); + hscr.set_state_type(static_cast( + eh->has_been_checked() ? eh->get_state_type() + : engine::notifier::hard)); + hscr.set_scheduled_downtime_depth(eh->get_scheduled_downtime_depth()); - // Acknowledgement event. - auto it = gl_acknowledgements.find(std::make_pair(hscr.host_id(), 0u)); - if (it != gl_acknowledgements.end() && - hscr.acknowledgement_type() == AckType::NONE) { - if (it->second->type() == make_type(io::neb, de_pb_acknowledgement)) { - neb_logger->debug("acknowledgement found on host {}", hscr.host_id()); - neb::pb_acknowledgement* a = - static_cast(it->second.get()); - if (!(!hscr.state() // !(OK or (normal ack and NOK)) - || (!a->obj().sticky() && - hscr.state() != static_cast(a->obj().state())))) { - a->mut_obj().set_deletion_time(time(nullptr)); - gl_publisher.write(std::move(it->second)); - } - } else { - neb::acknowledgement* a = - static_cast(it->second.get()); - if (!(!hscr.state() // !(OK or (normal ack and NOK)) - || (!a->is_sticky && hscr.state() != a->state))) { - a->deletion_time = time(nullptr); - gl_publisher.write(std::move(it->second)); - } - } - gl_acknowledgements.erase(it); + // Send event(s). + gl_publisher.write(h); + + // Acknowledgement event. + handle_acknowledgement(state, hscr); } neb_logger->debug("Still {} running acknowledgements", gl_acknowledgements.size()); @@ -2857,6 +2869,50 @@ int neb::callback_service(int callback_type, void* data) { return 0; } +template +static void fill_service_type(SrvStatus& ss, + const com::centreon::engine::service* es) { + switch (es->get_service_type()) { + case com::centreon::engine::service_type::METASERVICE: { + ss.set_type(METASERVICE); + uint64_t iid; + if (absl::SimpleAtoi(es->description().c_str() + 5, &iid)) + ss.set_internal_id(iid); + else { + SPDLOG_LOGGER_ERROR( + neb_logger, + "callbacks: service ('{}', '{}') looks like a meta-service but " + "its name is malformed", + es->get_hostname(), es->description()); + } + } break; + case com::centreon::engine::service_type::BA: { + ss.set_type(BA); + uint64_t iid; + if (absl::SimpleAtoi(es->description().c_str() + 3, &iid)) + ss.set_internal_id(iid); + else { + SPDLOG_LOGGER_ERROR( + neb_logger, + "callbacks: service ('{}', '{}') looks like a business-activity " + "but its name is malformed", + es->get_hostname(), es->description()); + } + } break; + case com::centreon::engine::service_type::ANOMALY_DETECTION: + ss.set_type(ANOMALY_DETECTION); + { + auto ad = + static_cast(es); + ss.set_internal_id(ad->get_internal_id()); + } + break; + default: + ss.set_type(SERVICE); + break; + } +} + /** * @brief Function that process protobuf service data. * @@ -2884,40 +2940,69 @@ int neb::callback_pb_service(int callback_type [[maybe_unused]], void* data) { if (ds->type == NEBTYPE_ADAPTIVESERVICE_UPDATE && ds->modified_attribute != MODATTR_ALL) { auto s{std::make_shared()}; + bool done = false; AdaptiveService& srv = s.get()->mut_obj(); - if (ds->modified_attribute & MODATTR_NOTIFICATIONS_ENABLED) + if (ds->modified_attribute & MODATTR_NOTIFICATIONS_ENABLED) { srv.set_notify(es->get_notifications_enabled()); - else if (ds->modified_attribute & MODATTR_ACTIVE_CHECKS_ENABLED) { + done = true; + } + if (ds->modified_attribute & MODATTR_ACTIVE_CHECKS_ENABLED) { srv.set_active_checks(es->active_checks_enabled()); srv.set_should_be_scheduled(es->get_should_be_scheduled()); - } else if (ds->modified_attribute & MODATTR_PASSIVE_CHECKS_ENABLED) + done = true; + } + if (ds->modified_attribute & MODATTR_PASSIVE_CHECKS_ENABLED) { srv.set_passive_checks(es->passive_checks_enabled()); - else if (ds->modified_attribute & MODATTR_EVENT_HANDLER_ENABLED) + done = true; + } + if (ds->modified_attribute & MODATTR_EVENT_HANDLER_ENABLED) { srv.set_event_handler_enabled(es->event_handler_enabled()); - else if (ds->modified_attribute & MODATTR_FLAP_DETECTION_ENABLED) + done = true; + } + if (ds->modified_attribute & MODATTR_FLAP_DETECTION_ENABLED) { srv.set_flap_detection_enabled(es->flap_detection_enabled()); - else if (ds->modified_attribute & MODATTR_OBSESSIVE_HANDLER_ENABLED) + done = true; + } + if (ds->modified_attribute & MODATTR_OBSESSIVE_HANDLER_ENABLED) { srv.set_obsess_over_service(es->obsess_over()); - else if (ds->modified_attribute & MODATTR_EVENT_HANDLER_COMMAND) + done = true; + } + if (ds->modified_attribute & MODATTR_EVENT_HANDLER_COMMAND) { srv.set_event_handler(common::check_string_utf8(es->event_handler())); - else if (ds->modified_attribute & MODATTR_CHECK_COMMAND) + done = true; + } + if (ds->modified_attribute & MODATTR_CHECK_COMMAND) { srv.set_check_command(common::check_string_utf8(es->check_command())); - else if (ds->modified_attribute & MODATTR_NORMAL_CHECK_INTERVAL) + done = true; + } + if (ds->modified_attribute & MODATTR_NORMAL_CHECK_INTERVAL) { srv.set_check_interval(es->check_interval()); - else if (ds->modified_attribute & MODATTR_RETRY_CHECK_INTERVAL) + done = true; + } + if (ds->modified_attribute & MODATTR_RETRY_CHECK_INTERVAL) { srv.set_retry_interval(es->retry_interval()); - else if (ds->modified_attribute & MODATTR_MAX_CHECK_ATTEMPTS) + done = true; + } + if (ds->modified_attribute & MODATTR_MAX_CHECK_ATTEMPTS) { srv.set_max_check_attempts(es->max_check_attempts()); - else if (ds->modified_attribute & MODATTR_FRESHNESS_CHECKS_ENABLED) + done = true; + } + if (ds->modified_attribute & MODATTR_FRESHNESS_CHECKS_ENABLED) { srv.set_check_freshness(es->check_freshness_enabled()); - else if (ds->modified_attribute & MODATTR_CHECK_TIMEPERIOD) + done = true; + } + if (ds->modified_attribute & MODATTR_CHECK_TIMEPERIOD) { srv.set_check_period(es->check_period()); - else if (ds->modified_attribute & MODATTR_NOTIFICATION_TIMEPERIOD) + done = true; + } + if (ds->modified_attribute & MODATTR_NOTIFICATION_TIMEPERIOD) { srv.set_notification_period(es->notification_period()); - else { - SPDLOG_LOGGER_ERROR(neb_logger, - "callbacks: adaptive service not implemented."); - assert(1 == 0); + done = true; + } + if (!done) { + SPDLOG_LOGGER_ERROR( + neb_logger, "callbacks: adaptive service field {} not implemented.", + ds->modified_attribute); } std::pair p{ engine::get_host_and_service_id(es->get_hostname(), es->description())}; @@ -2990,58 +3075,12 @@ int neb::callback_pb_service(int callback_type [[maybe_unused]], void* data) { srv.set_high_flap_threshold(es->get_high_flap_threshold()); if (!es->description().empty()) srv.set_description(common::check_string_utf8(es->description())); - if (!es->get_hostname().empty()) { std::string name{common::check_string_utf8(es->get_hostname())}; - switch (es->get_service_type()) { - case com::centreon::engine::service_type::METASERVICE: { - srv.set_type(METASERVICE); - uint64_t iid = 0; - for (auto c = srv.description().begin() + 5; - c != srv.description().end(); ++c) { - if (!isdigit(*c)) { - SPDLOG_LOGGER_ERROR( - neb_logger, - "callbacks: service ('{}', '{}') looks like a meta-service " - "but its name is malformed", - name, srv.description()); - break; - } - iid = 10 * iid + (*c - '0'); - } - srv.set_internal_id(iid); - } break; - case com::centreon::engine::service_type::BA: { - srv.set_type(BA); - uint64_t iid = 0; - for (auto c = srv.description().begin() + 3; - c != srv.description().end(); ++c) { - if (!isdigit(*c)) { - SPDLOG_LOGGER_ERROR( - neb_logger, - "callbacks: service ('{}', '{}') looks like a " - "business-activity but its name is malformed", - name, srv.description()); - break; - } - iid = 10 * iid + (*c - '0'); - } - srv.set_internal_id(iid); - } break; - case com::centreon::engine::service_type::ANOMALY_DETECTION: - srv.set_type(ANOMALY_DETECTION); - { - auto ad = - static_cast(es); - srv.set_internal_id(ad->get_internal_id()); - } - break; - default: - srv.set_type(SERVICE); - break; - } *srv.mutable_host_name() = std::move(name); } + fill_service_type(srv, es); + if (!es->get_icon_image().empty()) *srv.mutable_icon_image() = common::check_string_utf8(es->get_icon_image()); @@ -3386,140 +3425,132 @@ int32_t neb::callback_pb_service_status(int callback_type [[maybe_unused]], SPDLOG_LOGGER_DEBUG( neb_logger, "callbacks: generating pb service status check result event"); - const engine::service* es{static_cast( - static_cast(data)->object_ptr)}; - neb_logger->debug("callbacks: pb_service_status ({},{}) status {}, type {}", - es->host_id(), es->service_id(), - static_cast(es->get_current_state()), - static_cast(es->get_check_type())); - - auto s{std::make_shared()}; - ServiceStatus& sscr = s.get()->mut_obj(); - - sscr.set_host_id(es->host_id()); - sscr.set_service_id(es->service_id()); - if (es->host_id() == 0 || es->service_id() == 0) - SPDLOG_LOGGER_ERROR(neb_logger, "could not find ID of service ('{}', '{}')", - es->get_hostname(), es->description()); - - if (es->problem_has_been_acknowledged()) - sscr.set_acknowledgement_type(es->get_acknowledgement()); - else - sscr.set_acknowledgement_type(AckType::NONE); - - sscr.set_check_type( - static_cast(es->get_check_type())); - sscr.set_check_attempt(es->get_current_attempt()); - sscr.set_state(static_cast( - es->has_been_checked() ? es->get_current_state() : 4)); // Pending state. - sscr.set_execution_time(es->get_execution_time()); - sscr.set_checked(es->has_been_checked()); - sscr.set_flapping(es->get_is_flapping()); - sscr.set_last_check(es->get_last_check()); - sscr.set_last_hard_state( - static_cast(es->get_last_hard_state())); - sscr.set_last_hard_state_change(es->get_last_hard_state_change()); - sscr.set_last_notification(es->get_last_notification()); - sscr.set_notification_number(es->get_notification_number()); - sscr.set_last_state_change(es->get_last_state_change()); - sscr.set_last_time_critical(es->get_last_time_critical()); - sscr.set_last_time_ok(es->get_last_time_ok()); - sscr.set_last_time_unknown(es->get_last_time_unknown()); - sscr.set_last_time_warning(es->get_last_time_warning()); - sscr.set_latency(es->get_latency()); - sscr.set_next_check(es->get_next_check()); - sscr.set_next_notification(es->get_next_notification()); - sscr.set_no_more_notifications(es->get_no_more_notifications()); - if (!es->get_plugin_output().empty()) - sscr.set_output(common::check_string_utf8(es->get_plugin_output())); - if (!es->get_long_plugin_output().empty()) - sscr.set_long_output( - common::check_string_utf8(es->get_long_plugin_output())); - sscr.set_percent_state_change(es->get_percent_state_change()); - if (!es->get_perf_data().empty()) { - sscr.set_perfdata(common::check_string_utf8(es->get_perf_data())); - SPDLOG_LOGGER_TRACE(neb_logger, - "callbacks: service ({}, {}) has perfdata <<{}>>", - es->host_id(), es->service_id(), es->get_perf_data()); - } else { - SPDLOG_LOGGER_TRACE(neb_logger, - "callbacks: service ({}, {}) has no perfdata", - es->host_id(), es->service_id()); - } - sscr.set_should_be_scheduled(es->get_should_be_scheduled()); - sscr.set_state_type(static_cast( - es->has_been_checked() ? es->get_state_type() : engine::notifier::hard)); - sscr.set_scheduled_downtime_depth(es->get_scheduled_downtime_depth()); - - if (!es->get_hostname().empty()) { - if (strncmp(es->get_hostname().c_str(), "_Module_Meta", 13) == 0) { - if (strncmp(es->description().c_str(), "meta_", 5) == 0) { - sscr.set_type(METASERVICE); - uint64_t iid = 0; - for (auto c = es->description().begin() + 5; - c != es->description().end(); ++c) { - if (!isdigit(*c)) { - SPDLOG_LOGGER_ERROR( - neb_logger, - "callbacks: service ('{}', '{}') looks like a meta-service " - "but its name is malformed", - es->get_hostname(), es->description()); - break; - } - iid = 10 * iid + (*c - '0'); + nebstruct_service_status_data* ds = + static_cast(data); + const engine::service* es = static_cast(ds->object_ptr); + neb_logger->debug( + "callbacks: pb_service_status ({},{}) status {}, attributes {}, type {}", + es->host_id(), es->service_id(), + static_cast(es->get_current_state()), ds->attributes, + static_cast(es->get_check_type())); + + auto handle_acknowledgement = [](uint16_t state, auto& r) { + neb_logger->debug("Looking for acknowledgement on service ({}:{})", + r.host_id(), r.service_id()); + auto it = + gl_acknowledgements.find(std::make_pair(r.host_id(), r.service_id())); + if (it != gl_acknowledgements.end() && + r.acknowledgement_type() == AckType::NONE) { + neb_logger->debug("acknowledgement found on service ({}:{})", r.host_id(), + r.service_id()); + if (it->second->type() == make_type(io::neb, de_pb_acknowledgement)) { + neb::pb_acknowledgement* a = + static_cast(it->second.get()); + if (!(!state // !(OK or (normal ack and NOK)) + || (!a->obj().sticky() && state != a->obj().state()))) { + a->mut_obj().set_deletion_time(time(nullptr)); + gl_publisher.write(std::move(it->second)); } - sscr.set_internal_id(iid); - } - } else if (strncmp(es->get_hostname().c_str(), "_Module_BAM", 11) == 0) { - if (strncmp(es->description().c_str(), "ba_", 3) == 0) { - sscr.set_type(BA); - uint64_t iid = 0; - for (auto c = es->description().begin() + 3; - c != es->description().end(); ++c) { - if (!isdigit(*c)) { - SPDLOG_LOGGER_ERROR(neb_logger, - "callbacks: service ('{}', '{}') looks like a " - "business-activity but its name is malformed", - es->get_hostname(), es->description()); - break; - } - iid = 10 * iid + (*c - '0'); + } else { + neb::acknowledgement* a = + static_cast(it->second.get()); + if (!(!state // !(OK or (normal ack and NOK)) + || (!a->is_sticky && state != a->state))) { + a->deletion_time = time(nullptr); + gl_publisher.write(std::move(it->second)); } - sscr.set_internal_id(iid); } + gl_acknowledgements.erase(it); } - } - // Send event(s). - gl_publisher.write(s); + }; + uint16_t state = + es->has_been_checked() ? es->get_current_state() : 4; // Pending state. + if (ds->attributes != engine::service::STATUS_ALL) { + auto as = std::make_shared(); + AdaptiveServiceStatus& asscr = as.get()->mut_obj(); + fill_service_type(asscr, es); + if (ds->attributes & engine::service::STATUS_DOWNTIME_DEPTH) { + asscr.set_host_id(es->host_id()); + asscr.set_service_id(es->service_id()); + asscr.set_scheduled_downtime_depth(es->get_scheduled_downtime_depth()); + } + if (ds->attributes & engine::service::STATUS_NOTIFICATION_NUMBER) { + asscr.set_host_id(es->host_id()); + asscr.set_service_id(es->service_id()); + asscr.set_notification_number(es->get_notification_number()); + } + if (ds->attributes & engine::service::STATUS_ACKNOWLEDGEMENT) { + asscr.set_host_id(es->host_id()); + asscr.set_service_id(es->service_id()); + asscr.set_acknowledgement_type(es->get_acknowledgement()); + } + gl_publisher.write(as); - neb_logger->debug("Looking for acknowledgement on service ({}:{})", - sscr.host_id(), sscr.service_id()); - // Acknowledgement event. - auto it = gl_acknowledgements.find( - std::make_pair(sscr.host_id(), sscr.service_id())); - if (it != gl_acknowledgements.end() && - sscr.acknowledgement_type() == AckType::NONE) { - neb_logger->debug("acknowledgement found on service ({}:{})", - sscr.host_id(), sscr.service_id()); - if (it->second->type() == make_type(io::neb, de_pb_acknowledgement)) { - neb::pb_acknowledgement* a = - static_cast(it->second.get()); - if (!(!sscr.state() // !(OK or (normal ack and NOK)) - || (!a->obj().sticky() && - static_cast(sscr.state()) != a->obj().state()))) { - a->mut_obj().set_deletion_time(time(nullptr)); - gl_publisher.write(std::move(it->second)); - } + // Acknowledgement event. + handle_acknowledgement(state, asscr); + } else { + auto s{std::make_shared()}; + ServiceStatus& sscr = s.get()->mut_obj(); + + fill_service_type(sscr, es); + sscr.set_host_id(es->host_id()); + sscr.set_service_id(es->service_id()); + if (es->host_id() == 0 || es->service_id() == 0) + SPDLOG_LOGGER_ERROR(neb_logger, + "could not find ID of service ('{}', '{}')", + es->get_hostname(), es->description()); + + sscr.set_acknowledgement_type(es->get_acknowledgement()); + + sscr.set_check_type( + static_cast(es->get_check_type())); + sscr.set_check_attempt(es->get_current_attempt()); + sscr.set_state(static_cast(state)); + sscr.set_execution_time(es->get_execution_time()); + sscr.set_checked(es->has_been_checked()); + sscr.set_flapping(es->get_is_flapping()); + sscr.set_last_check(es->get_last_check()); + sscr.set_last_hard_state( + static_cast(es->get_last_hard_state())); + sscr.set_last_hard_state_change(es->get_last_hard_state_change()); + sscr.set_last_notification(es->get_last_notification()); + sscr.set_notification_number(es->get_notification_number()); + sscr.set_last_state_change(es->get_last_state_change()); + sscr.set_last_time_critical(es->get_last_time_critical()); + sscr.set_last_time_ok(es->get_last_time_ok()); + sscr.set_last_time_unknown(es->get_last_time_unknown()); + sscr.set_last_time_warning(es->get_last_time_warning()); + sscr.set_latency(es->get_latency()); + sscr.set_next_check(es->get_next_check()); + sscr.set_next_notification(es->get_next_notification()); + sscr.set_no_more_notifications(es->get_no_more_notifications()); + if (!es->get_plugin_output().empty()) + sscr.set_output(common::check_string_utf8(es->get_plugin_output())); + if (!es->get_long_plugin_output().empty()) + sscr.set_long_output( + common::check_string_utf8(es->get_long_plugin_output())); + sscr.set_percent_state_change(es->get_percent_state_change()); + if (!es->get_perf_data().empty()) { + sscr.set_perfdata(common::check_string_utf8(es->get_perf_data())); + SPDLOG_LOGGER_TRACE(neb_logger, + "callbacks: service ({}, {}) has perfdata <<{}>>", + es->host_id(), es->service_id(), es->get_perf_data()); } else { - neb::acknowledgement* a = - static_cast(it->second.get()); - if (!(!sscr.state() // !(OK or (normal ack and NOK)) - || (!a->is_sticky && sscr.state() != a->state))) { - a->deletion_time = time(nullptr); - gl_publisher.write(std::move(it->second)); - } + SPDLOG_LOGGER_TRACE(neb_logger, + "callbacks: service ({}, {}) has no perfdata", + es->host_id(), es->service_id()); } - gl_acknowledgements.erase(it); + sscr.set_should_be_scheduled(es->get_should_be_scheduled()); + sscr.set_state_type(static_cast( + es->has_been_checked() ? es->get_state_type() + : engine::notifier::hard)); + sscr.set_scheduled_downtime_depth(es->get_scheduled_downtime_depth()); + + // Send event(s). + gl_publisher.write(s); + + // Acknowledgement event. + handle_acknowledgement(state, sscr); } neb_logger->debug("Still {} running acknowledgements", gl_acknowledgements.size()); diff --git a/broker/tls/inc/com/centreon/broker/tls/stream.hh b/broker/tls/inc/com/centreon/broker/tls/stream.hh index 57274cb75be..300fb722e85 100644 --- a/broker/tls/inc/com/centreon/broker/tls/stream.hh +++ b/broker/tls/inc/com/centreon/broker/tls/stream.hh @@ -19,7 +19,6 @@ #ifndef CCB_TLS_STREAM_HH #define CCB_TLS_STREAM_HH -#include #include "com/centreon/broker/io/stream.hh" #include "com/centreon/broker/tls/params.hh" diff --git a/broker/tls/test/acceptor.cc b/broker/tls/test/acceptor.cc index f2a051b4fc0..d6a32c82016 100644 --- a/broker/tls/test/acceptor.cc +++ b/broker/tls/test/acceptor.cc @@ -19,10 +19,8 @@ #include "com/centreon/broker/tcp/acceptor.hh" -#include #include -#include #include "com/centreon/broker/io/raw.hh" #include "com/centreon/broker/misc/buffer.hh" @@ -34,7 +32,6 @@ #include "com/centreon/broker/tls/connector.hh" #include "com/centreon/broker/tls/internal.hh" #include "com/centreon/broker/tls/stream.hh" -#include "com/centreon/common/pool.hh" #include "com/centreon/exceptions/msg_fmt.hh" using namespace com::centreon::broker; @@ -178,7 +175,7 @@ TEST_F(TlsTest, AnonTlsStreamContinuous) { tls::stream* tls_centengine = static_cast(io_tls_centengine.get()); - char str[20]; + char str[24]; int i = 0; /* This is not representative of a real stream. Here we have to call write diff --git a/broker/unified_sql/inc/com/centreon/broker/unified_sql/stream.hh b/broker/unified_sql/inc/com/centreon/broker/unified_sql/stream.hh index 1a86768f5c9..f2ecb8136b0 100644 --- a/broker/unified_sql/inc/com/centreon/broker/unified_sql/stream.hh +++ b/broker/unified_sql/inc/com/centreon/broker/unified_sql/stream.hh @@ -18,8 +18,6 @@ #ifndef CCB_UNIFIED_SQL_STREAM_HH #define CCB_UNIFIED_SQL_STREAM_HH -#include -#include #include #include #include @@ -437,11 +435,13 @@ class stream : public io::stream { void _process_pb_host(const std::shared_ptr& d); uint64_t _process_pb_host_in_resources(const Host& h, int32_t conn); void _process_pb_host_status(const std::shared_ptr& d); + void _process_pb_adaptive_host_status(const std::shared_ptr& d); void _process_pb_adaptive_host(const std::shared_ptr& d); void _process_pb_service(const std::shared_ptr& d); uint64_t _process_pb_service_in_resources(const Service& s, int32_t conn); void _process_pb_adaptive_service(const std::shared_ptr& d); void _process_pb_service_status(const std::shared_ptr& d); + void _process_pb_adaptive_service_status(const std::shared_ptr& d); void _process_severity(const std::shared_ptr& d); void _process_tag(const std::shared_ptr& d); void _process_pb_log(const std::shared_ptr& d); diff --git a/broker/unified_sql/src/stream.cc b/broker/unified_sql/src/stream.cc index 8ee2af74538..9547b43c742 100644 --- a/broker/unified_sql/src/stream.cc +++ b/broker/unified_sql/src/stream.cc @@ -118,7 +118,9 @@ constexpr void (stream::*const stream::neb_processing_table[])( &stream::_process_pb_service_group, &stream::_process_pb_service_group_member, &stream::_process_pb_host_parent, - nullptr // pb_instance_configuration + nullptr, // pb_instance_configuration + &stream::_process_pb_adaptive_service_status, + &stream::_process_pb_adaptive_host_status, }; constexpr size_t neb_processing_table_size = diff --git a/broker/unified_sql/src/stream_sql.cc b/broker/unified_sql/src/stream_sql.cc index 5ad2836dbeb..0e24d255439 100644 --- a/broker/unified_sql/src/stream_sql.cc +++ b/broker/unified_sql/src/stream_sql.cc @@ -15,16 +15,12 @@ * * For more information : contact@centreon.com */ -#include -#include #include "bbdo/neb.pb.h" #include "bbdo/storage/index_mapping.hh" #include "com/centreon/broker/cache/global_cache.hh" -#include "com/centreon/broker/config/applier/state.hh" #include "com/centreon/broker/misc/string.hh" #include "com/centreon/broker/neb/events.hh" -#include "com/centreon/broker/sql/mysql_result.hh" #include "com/centreon/broker/sql/query_preparator.hh" #include "com/centreon/broker/sql/table_max_size.hh" #include "com/centreon/broker/unified_sql/internal.hh" @@ -852,10 +848,8 @@ void stream::_process_downtime(const std::shared_ptr& d) { SPDLOG_LOGGER_INFO(_logger_sql, "unified_sql: processing downtime event (poller: {}" ", host: {}, service: {}, start time: {}, end_time: {}" - ", actual start time: {}" - ", actual end time: {}" - ", duration: {}, entry time: {}" - ", deletion time: {})", + ", actual start time: {}, actual end time: {}, duration: " + "{}, entry time: {}, deletion time: {})", dd.poller_id, dd.host_id, dd.service_id, dd.start_time, dd.end_time, dd.actual_start_time, dd.actual_end_time, dd.duration, dd.entry_time, dd.deletion_time); @@ -950,11 +944,9 @@ void stream::_process_pb_downtime(const std::shared_ptr& d) { // Log message. SPDLOG_LOGGER_INFO(_logger_sql, "unified_sql: processing pb downtime event (poller: {}" - ", host: {}, service: {}, start time: {}, end_time: {}" - ", actual start time: {}" - ", actual end time: {}" - ", duration: {}, entry time: {}" - ", deletion time: {})", + ", host: {}, service: {}, start time: {}, end_time: {}, " + "actual start time: {}, actual end time: {}, duration: " + "{}, entry time: {}, deletion time: {})", dt_obj.instance_id(), dt_obj.host_id(), dt_obj.service_id(), dt_obj.start_time(), dt_obj.end_time(), dt_obj.actual_start_time(), @@ -2568,6 +2560,80 @@ void stream::_process_pb_host_status(const std::shared_ptr& d) { now, hscr.state(), hscr.state_type()); } +void stream::_process_pb_adaptive_host_status( + const std::shared_ptr& d) { + _finish_action( + -1, actions::host_parents | actions::comments | actions::downtimes); + // Processed object. + auto h{static_cast(d.get())}; + auto& hscr = h->obj(); + + SPDLOG_LOGGER_DEBUG( + _logger_sql, "unified_sql: pb adaptive host {} status -{}{}{}", + hscr.host_id(), + hscr.has_acknowledgement_type() ? " with acknowledgement type" : "", + hscr.has_notification_number() ? " with notification number" : "", + hscr.has_scheduled_downtime_depth() ? " with scheduled downtime depth" + : ""); + + if (!_host_instance_known(hscr.host_id())) { + SPDLOG_LOGGER_WARN(_logger_sql, + "unified_sql: pb adaptive host status {} thrown away " + "because host {} is not known by " + "any poller", + hscr.host_id(), hscr.host_id()); + return; + } + + int32_t conn = _mysql.choose_connection_by_instance( + _cache_host_instance[static_cast(hscr.host_id())]); + + if (_store_in_hosts_services) { + constexpr std::string_view buf("UPDATE hosts SET "); + std::string query{buf}; + if (hscr.has_acknowledgement_type()) + query += fmt::format("acknowledged='{}',acknowledgement_type='{}',", + hscr.acknowledgement_type() != AckType::NONE ? 1 : 0, + hscr.acknowledgement_type()); + if (hscr.has_notification_number()) + query += + fmt::format("notification_number={},", hscr.notification_number()); + if (hscr.has_scheduled_downtime_depth()) + query += fmt::format("scheduled_downtime_depth={},", + hscr.scheduled_downtime_depth()); + if (query.size() > buf.size()) { + query.resize(query.size() - 1); + query += fmt::format(" WHERE host_id={}", hscr.host_id()); + SPDLOG_LOGGER_TRACE(_logger_sql, "unified_sql: query <<{}>>", query); + _mysql.run_query(query, database::mysql_error::store_host_status, conn); + _add_action(conn, actions::hosts); + } + } + + if (_store_in_resources) { + constexpr std::string_view res_buf("UPDATE resources SET "); + std::string res_query{res_buf}; + if (hscr.has_acknowledgement_type()) + res_query += + fmt::format("acknowledged='{}',", + hscr.acknowledgement_type() != AckType::NONE ? 1 : 0); + if (hscr.has_notification_number()) + res_query += + fmt::format("notification_number={},", hscr.notification_number()); + if (hscr.has_scheduled_downtime_depth()) + res_query += + fmt::format("in_downtime={},", hscr.scheduled_downtime_depth() > 0); + if (res_query.size() > res_buf.size()) { + res_query.resize(res_query.size() - 1); + res_query += fmt::format(" WHERE parent_id=0 AND id={}", hscr.host_id()); + SPDLOG_LOGGER_TRACE(_logger_sql, "unified_sql: query <<{}>>", res_query); + _mysql.run_query(res_query, database::mysql_error::update_resources, + conn); + _add_action(conn, actions::resources); + } + } +} + /** * Process an instance event. The thread executing the command is * controlled so that queries depending on this one will be made by the same @@ -2636,8 +2702,8 @@ void stream::_process_pb_instance(const std::shared_ptr& d) { actions::comments | actions::servicegroups | actions::hostgroups); - /* Now, the local::pb_stop is handled by unified_sql. So the pb_instance with - * running = false, seems no more useful. */ + /* Now, the local::pb_stop is handled by unified_sql. So the pb_instance + * with running = false, seems no more useful. */ // Log message. SPDLOG_LOGGER_INFO( _logger_sql, @@ -2746,10 +2812,10 @@ void stream::_process_pb_instance_status(const std::shared_ptr& d) { actions::comments); // Log message. - SPDLOG_LOGGER_DEBUG( - _logger_sql, - "unified_sql: processing poller status event (id: {}, last alive: {} {})", - is.instance_id(), is.last_alive(), is.ShortDebugString()); + SPDLOG_LOGGER_DEBUG(_logger_sql, + "unified_sql: processing poller status event (id: {}, " + "last alive: {} {})", + is.instance_id(), is.last_alive(), is.ShortDebugString()); // Processing. if (_is_valid_poller(is.instance_id())) { @@ -2885,10 +2951,10 @@ void stream::_process_pb_log(const std::shared_ptr& d) { const auto& le_obj = le.obj(); // Log message. - SPDLOG_LOGGER_INFO( - _logger_sql, - "unified_sql: processing pb log of poller '{}' generated at {} (type {})", - le_obj.instance_name(), le_obj.ctime(), le_obj.msg_type()); + SPDLOG_LOGGER_INFO(_logger_sql, + "unified_sql: processing pb log of poller '{}' " + "generated at {} (type {})", + le_obj.instance_name(), le_obj.ctime(), le_obj.msg_type()); if (_logs->is_bulk()) { auto binder = [&](database::mysql_bulk_bind& b) { @@ -3448,10 +3514,10 @@ void stream::_process_service(const std::shared_ptr& d) { // Processed object. const neb::service& s(*static_cast(d.get())); if (!_host_instance_known(s.host_id)) { - SPDLOG_LOGGER_WARN( - _logger_sql, - "unified_sql: service ({0}, {1}) thrown away because host {0} unknown", - s.host_id, s.service_id); + SPDLOG_LOGGER_WARN(_logger_sql, + "unified_sql: service ({0}, {1}) thrown away because " + "host {0} unknown", + s.host_id, s.service_id); return; } auto cache_ptr = cache::global_cache::instance_ptr(); @@ -3757,6 +3823,9 @@ uint64_t stream::_process_pb_service_in_resources(const Service& s, 5, svc_ordered_status[s.state()]); _resources_service_insert.bind_value_as_u64_ext( 6, s.last_state_change(), mapping::entry::invalid_on_zero); + _logger_sql->debug("service1 ({}, {}) scheduled_downtime_depth: {}", + s.host_id(), s.service_id(), + s.scheduled_downtime_depth()); _resources_service_insert.bind_value_as_bool( 7, s.scheduled_downtime_depth() > 0); _resources_service_insert.bind_value_as_bool( @@ -3850,6 +3919,9 @@ uint64_t stream::_process_pb_service_in_resources(const Service& s, 3, svc_ordered_status[s.state()]); _resources_service_update.bind_value_as_u64_ext( 4, s.last_state_change(), mapping::entry::invalid_on_zero); + _logger_sql->debug("service2 ({}, {}) scheduled_downtime_depth: {}", + s.host_id(), s.service_id(), + s.scheduled_downtime_depth()); _resources_service_update.bind_value_as_bool( 5, s.scheduled_downtime_depth() > 0); _resources_service_update.bind_value_as_bool( @@ -3990,96 +4062,98 @@ void stream::_process_pb_adaptive_service(const std::shared_ptr& d) { int32_t conn = _mysql.choose_connection_by_instance( _cache_host_instance[static_cast(as.host_id())]); - constexpr std::string_view buf("UPDATE services SET"); - std::string query{buf.data(), buf.size()}; - if (as.has_notify()) - query += fmt::format(" notify='{}',", as.notify() ? 1 : 0); - if (as.has_active_checks()) - query += fmt::format(" active_checks='{}',", as.active_checks() ? 1 : 0); - if (as.has_should_be_scheduled()) - query += fmt::format(" should_be_scheduled='{}',", - as.should_be_scheduled() ? 1 : 0); - if (as.has_passive_checks()) - query += fmt::format(" passive_checks='{}',", as.passive_checks() ? 1 : 0); - if (as.has_event_handler_enabled()) - query += fmt::format(" event_handler_enabled='{}',", - as.event_handler_enabled() ? 1 : 0); - if (as.has_flap_detection_enabled()) - query += fmt::format(" flap_detection='{}',", - as.flap_detection_enabled() ? 1 : 0); - if (as.has_obsess_over_service()) - query += fmt::format(" obsess_over_service='{}',", - as.obsess_over_service() ? 1 : 0); - if (as.has_event_handler()) - query += fmt::format( - " event_handler='{}',", - misc::string::escape(as.event_handler(), - get_centreon_storage_services_col_size( - centreon_storage_services_event_handler))); - if (as.has_check_command()) - query += fmt::format( - " check_command='{}',", - misc::string::escape(as.check_command(), - get_centreon_storage_services_col_size( - centreon_storage_services_check_command))); - if (as.has_check_interval()) - query += fmt::format(" check_interval={},", as.check_interval()); - if (as.has_retry_interval()) - query += fmt::format(" retry_interval={},", as.retry_interval()); - if (as.has_max_check_attempts()) - query += fmt::format(" max_check_attempts={},", as.max_check_attempts()); - if (as.has_check_freshness()) - query += - fmt::format(" check_freshness='{}',", as.check_freshness() ? 1 : 0); - if (as.has_check_period()) - query += fmt::format( - " check_period='{}',", - misc::string::escape(as.check_period(), - get_centreon_storage_services_col_size( - centreon_storage_services_check_period))); - if (as.has_notification_period()) - query += - fmt::format(" notification_period='{}',", - misc::string::escape( - as.notification_period(), - get_centreon_storage_services_col_size( - centreon_storage_services_notification_period))); - - // If nothing was added to query, we can exit immediately. - if (query.size() > buf.size()) { - query.resize(query.size() - 1); - query += fmt::format(" WHERE host_id={} AND service_id={}", as.host_id(), - as.service_id()); - SPDLOG_LOGGER_TRACE(_logger_sql, "unified_sql: query <<{}>>", query); - _mysql.run_query(query, database::mysql_error::store_service, conn); - _add_action(conn, actions::services); - - if (_store_in_resources) { - constexpr std::string_view res_buf("UPDATE resources SET"); - std::string res_query{res_buf.data(), res_buf.size()}; - if (as.has_notify()) - res_query += - fmt::format(" notifications_enabled='{}',", as.notify() ? 1 : 0); - if (as.has_active_checks()) - res_query += fmt::format(" active_checks_enabled='{}',", - as.active_checks() ? 1 : 0); - if (as.has_passive_checks()) - res_query += fmt::format(" passive_checks_enabled='{}',", - as.passive_checks() ? 1 : 0); - if (as.has_max_check_attempts()) - res_query += - fmt::format(" max_check_attempts={},", as.max_check_attempts()); + if (_store_in_hosts_services) { + constexpr std::string_view buf("UPDATE services SET"); + std::string query{buf.data(), buf.size()}; + if (as.has_notify()) + query += fmt::format(" notify='{}',", as.notify() ? 1 : 0); + if (as.has_active_checks()) + query += fmt::format(" active_checks='{}',", as.active_checks() ? 1 : 0); + if (as.has_should_be_scheduled()) + query += fmt::format(" should_be_scheduled='{}',", + as.should_be_scheduled() ? 1 : 0); + if (as.has_passive_checks()) + query += + fmt::format(" passive_checks='{}',", as.passive_checks() ? 1 : 0); + if (as.has_event_handler_enabled()) + query += fmt::format(" event_handler_enabled='{}',", + as.event_handler_enabled() ? 1 : 0); + if (as.has_flap_detection_enabled()) + query += fmt::format(" flap_detection='{}',", + as.flap_detection_enabled() ? 1 : 0); + if (as.has_obsess_over_service()) + query += fmt::format(" obsess_over_service='{}',", + as.obsess_over_service() ? 1 : 0); + if (as.has_event_handler()) + query += fmt::format( + " event_handler='{}',", + misc::string::escape(as.event_handler(), + get_centreon_storage_services_col_size( + centreon_storage_services_event_handler))); + if (as.has_check_command()) + query += fmt::format( + " check_command='{}',", + misc::string::escape(as.check_command(), + get_centreon_storage_services_col_size( + centreon_storage_services_check_command))); + if (as.has_check_interval()) + query += fmt::format(" check_interval={},", as.check_interval()); + if (as.has_retry_interval()) + query += fmt::format(" retry_interval={},", as.retry_interval()); + if (as.has_max_check_attempts()) + query += fmt::format(" max_check_attempts={},", as.max_check_attempts()); + if (as.has_check_freshness()) + query += + fmt::format(" check_freshness='{}',", as.check_freshness() ? 1 : 0); + if (as.has_check_period()) + query += fmt::format( + " check_period='{}',", + misc::string::escape(as.check_period(), + get_centreon_storage_services_col_size( + centreon_storage_services_check_period))); + if (as.has_notification_period()) + query += + fmt::format(" notification_period='{}',", + misc::string::escape( + as.notification_period(), + get_centreon_storage_services_col_size( + centreon_storage_services_notification_period))); + + // If nothing was added to query, we can exit immediately. + if (query.size() > buf.size()) { + query.resize(query.size() - 1); + query += fmt::format(" WHERE host_id={} AND service_id={}", as.host_id(), + as.service_id()); + SPDLOG_LOGGER_TRACE(_logger_sql, "unified_sql: query <<{}>>", query); + _mysql.run_query(query, database::mysql_error::store_service, conn); + _add_action(conn, actions::services); + } + } - if (res_query.size() > res_buf.size()) { - res_query.resize(res_query.size() - 1); - res_query += fmt::format(" WHERE parent_id={} AND id={}", as.host_id(), - as.service_id()); - SPDLOG_LOGGER_TRACE(_logger_sql, "unified_sql: query <<{}>>", - res_query); - _mysql.run_query(res_query, database::mysql_error::update_resources, - conn); - _add_action(conn, actions::resources); - } + if (_store_in_resources) { + constexpr std::string_view res_buf("UPDATE resources SET"); + std::string res_query{res_buf.data(), res_buf.size()}; + if (as.has_notify()) + res_query += + fmt::format(" notifications_enabled='{}',", as.notify() ? 1 : 0); + if (as.has_active_checks()) + res_query += fmt::format(" active_checks_enabled='{}',", + as.active_checks() ? 1 : 0); + if (as.has_passive_checks()) + res_query += fmt::format(" passive_checks_enabled='{}',", + as.passive_checks() ? 1 : 0); + if (as.has_max_check_attempts()) + res_query += + fmt::format(" max_check_attempts={},", as.max_check_attempts()); + + if (res_query.size() > res_buf.size()) { + res_query.resize(res_query.size() - 1); + res_query += fmt::format(" WHERE parent_id={} AND id={}", as.host_id(), + as.service_id()); + SPDLOG_LOGGER_TRACE(_logger_sql, "unified_sql: query <<{}>>", res_query); + _mysql.run_query(res_query, database::mysql_error::update_resources, + conn); + _add_action(conn, actions::resources); } } } @@ -4263,7 +4337,8 @@ void stream::_process_service_status(const std::shared_ptr& d) { // Do nothing. SPDLOG_LOGGER_INFO( _logger_sql, - "unified_sql: not processing service status event (host: {}, service: " + "unified_sql: not processing service status event (host: {}, " + "service: " "{}, " "check type: {}, last check: {}, next check: {}, now: {}, state ({}, " "{}))", @@ -4369,6 +4444,9 @@ void stream::_process_pb_service_status(const std::shared_ptr& d) { mapping::entry::invalid_on_zero); b->set_value_as_bool(25, sscr.acknowledgement_type() != AckType::NONE); b->set_value_as_i32(26, sscr.acknowledgement_type()); + _logger_sql->debug("service3 ({}, {}) scheduled_downtime_depth: {}", + sscr.host_id(), sscr.service_id(), + sscr.scheduled_downtime_depth()); b->set_value_as_i32(27, sscr.scheduled_downtime_depth()); b->set_value_as_i32(28, sscr.host_id()); b->set_value_as_i32(29, sscr.service_id()); @@ -4424,6 +4502,9 @@ void stream::_process_pb_service_status(const std::shared_ptr& d) { _sscr_update->bind_value_as_bool( 25, sscr.acknowledgement_type() != AckType::NONE); _sscr_update->bind_value_as_i32(26, sscr.acknowledgement_type()); + _logger_sql->debug("service4 ({}, {}) scheduled_downtime_depth: {}", + sscr.host_id(), sscr.service_id(), + sscr.scheduled_downtime_depth()); _sscr_update->bind_value_as_i32(27, sscr.scheduled_downtime_depth()); _sscr_update->bind_value_as_i32(28, sscr.host_id()); _sscr_update->bind_value_as_i32(29, sscr.service_id()); @@ -4456,6 +4537,9 @@ void stream::_process_pb_service_status(const std::shared_ptr& d) { b->set_value_as_i32(1, svc_ordered_status[sscr.state()]); b->set_value_as_u64(2, sscr.last_state_change(), mapping::entry::invalid_on_zero); + _logger_sql->debug("service5 ({}, {}) scheduled_downtime_depth: {}", + sscr.host_id(), sscr.service_id(), + sscr.scheduled_downtime_depth()); b->set_value_as_bool(3, sscr.scheduled_downtime_depth() > 0); b->set_value_as_bool(4, sscr.acknowledgement_type() != AckType::NONE); b->set_value_as_bool(5, @@ -4477,13 +4561,17 @@ void stream::_process_pb_service_status(const std::shared_ptr& d) { b->current_row()); } else { _logger_sql->debug( - "unified_sql: NOT BULK pb service status ({}, {}) {} in resources", + "unified_sql: NOT BULK pb service status ({}, {}) {} in " + "resources", sscr.host_id(), sscr.service_id(), sscr.state()); _sscr_resources_update->bind_value_as_i32(0, sscr.state()); _sscr_resources_update->bind_value_as_i32( 1, svc_ordered_status[sscr.state()]); _sscr_resources_update->bind_value_as_u64_ext( 2, sscr.last_state_change(), mapping::entry::invalid_on_zero); + _logger_sql->debug("service6 ({}, {}) scheduled_downtime_depth: {}", + sscr.host_id(), sscr.service_id(), + sscr.scheduled_downtime_depth()); _sscr_resources_update->bind_value_as_bool( 3, sscr.scheduled_downtime_depth() > 0); _sscr_resources_update->bind_value_as_bool( @@ -4509,7 +4597,8 @@ void stream::_process_pb_service_status(const std::shared_ptr& d) { // Do nothing. SPDLOG_LOGGER_INFO( _logger_sql, - "unified_sql: not processing service status check result event (host: " + "unified_sql: not processing service status check result event " + "(host: " "{}, " "service: {}, " "check type: {}, last check: {}, next check: {}, now: {}, " @@ -4522,6 +4611,98 @@ void stream::_process_pb_service_status(const std::shared_ptr& d) { _unified_sql_process_pb_service_status(d); } +/** + * @brief Process an adaptive service status event. + * + * @param d The event to process. + */ +void stream::_process_pb_adaptive_service_status( + const std::shared_ptr& d) { + _finish_action( + -1, actions::host_parents | actions::comments | actions::downtimes); + // Processed object. + auto s{static_cast(d.get())}; + auto& sscr = s->obj(); + + SPDLOG_LOGGER_DEBUG( + _logger_sql, + "unified_sql: processing pb adaptive service status of ({}, {}) " + "-{}{}{}", + sscr.host_id(), sscr.service_id(), + sscr.has_acknowledgement_type() ? "with acknowledge type" : "", + sscr.has_notification_number() ? "with notification number" : "", + sscr.has_scheduled_downtime_depth() ? "with scheduled downtime depth" + : ""); + + if (!_host_instance_known(sscr.host_id())) { + SPDLOG_LOGGER_WARN( + _logger_sql, + "unified_sql: pb adaptive service status ({}, {}) thrown " + "away because host {} is not known by any poller", + sscr.host_id(), sscr.service_id(), sscr.host_id()); + return; + } + + int32_t conn = _mysql.choose_connection_by_instance( + _cache_host_instance[sscr.host_id()]); + + if (_store_in_hosts_services) { + constexpr std::string_view query("UPDATE services SET "); + std::string buf_query(query); + if (sscr.has_acknowledgement_type()) + buf_query += + fmt::format("acknowledged='{}',acknowledgement_type={},", + sscr.acknowledgement_type() != AckType::NONE ? 1 : 0, + sscr.acknowledgement_type()); + if (sscr.has_notification_number()) + buf_query += + fmt::format("notification_number={},", sscr.notification_number()); + _logger_sql->debug("service7 ({}, {}) scheduled_downtime_depth: {}", + sscr.host_id(), sscr.service_id(), + sscr.scheduled_downtime_depth()); + if (sscr.has_scheduled_downtime_depth()) + buf_query += fmt::format("scheduled_downtime_depth={},", + sscr.scheduled_downtime_depth()); + if (buf_query.size() > query.size()) { + buf_query.resize(buf_query.size() - 1); + buf_query += fmt::format(" WHERE host_id={} AND service_id={}", + sscr.host_id(), sscr.service_id()); + SPDLOG_LOGGER_TRACE(_logger_sql, "unified_sql: query <<{}>>", buf_query); + _mysql.run_query(buf_query, database::mysql_error::store_service_status, + conn); + _add_action(conn, actions::services); + } + } + + if (_store_in_resources) { + constexpr std::string_view res_query("UPDATE resources SET "); + std::string buf_res_query(res_query); + if (sscr.has_acknowledgement_type()) + buf_res_query += + fmt::format("acknowledged='{}',", + sscr.acknowledgement_type() != AckType::NONE ? 1 : 0); + if (sscr.has_notification_number()) + buf_res_query += + fmt::format("notification_number={},", sscr.notification_number()); + _logger_sql->debug("service8 ({}, {}) scheduled_downtime_depth: {}", + sscr.host_id(), sscr.service_id(), + sscr.scheduled_downtime_depth()); + if (sscr.has_scheduled_downtime_depth()) + buf_res_query += + fmt::format("in_downtime={},", sscr.scheduled_downtime_depth() > 0); + if (buf_res_query.size() > res_query.size()) { + buf_res_query.resize(buf_res_query.size() - 1); + buf_res_query += fmt::format(" WHERE parent_id={} AND id={}", + sscr.host_id(), sscr.service_id()); + SPDLOG_LOGGER_TRACE(_logger_sql, "unified_sql: query <<{}>>", + buf_res_query); + _mysql.run_query(buf_res_query, database::mysql_error::update_resources, + conn); + _add_action(conn, actions::resources); + } + } +} + void stream::_process_severity(const std::shared_ptr& d) { if (!_store_in_resources) return; diff --git a/ccc/client.cc b/ccc/client.cc index 52ca8be68c4..5c2ea11087c 100644 --- a/ccc/client.cc +++ b/ccc/client.cc @@ -1,5 +1,5 @@ /** - * Copyright 2022 Centreon + * Copyright 2024 Centreon * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,10 +36,13 @@ using namespace com::centreon::ccc; * @param channel The channel to use to the gRPC server. * @param color_enabled A boolean telling if we should use colors or not. */ -client::client(std::shared_ptr channel, bool color_enabled) +client::client(std::shared_ptr channel, + bool color_enabled, + bool always_print_primitive_fields) : _stub{std::make_unique(channel)}, _server{CCC_NONE}, - _color_enabled{color_enabled} { + _color_enabled{color_enabled}, + _always_print_primitive_fields{always_print_primitive_fields} { const ::google::protobuf::Empty e; com::centreon::broker::Version broker_v; com::centreon::engine::Version engine_v; @@ -210,6 +213,7 @@ std::string client::call(const std::string& cmd, const std::string& args) { std::string retval; google::protobuf::util::JsonPrintOptions json_options; json_options.add_whitespace = true; + json_options.always_print_primitive_fields = _always_print_primitive_fields; auto status = google::protobuf::util::MessageToJsonString( *output_message, &retval, json_options); diff --git a/ccc/client.hh b/ccc/client.hh index ce1132ab961..b11f2096a53 100644 --- a/ccc/client.hh +++ b/ccc/client.hh @@ -1,5 +1,5 @@ /* -** Copyright 2022 Centreon +** Copyright 2024 Centreon ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -48,10 +48,13 @@ class client { std::unique_ptr _stub; type _server; bool _color_enabled; + bool _always_print_primitive_fields; grpc::CompletionQueue _cq; public: - client(std::shared_ptr channel, bool color_enabled = true); + client(std::shared_ptr channel, + bool color_enabled = true, + bool _always_print_primitive_fields = false); std::list methods() const; std::string call(const std::string& cmd, const std::string& args); std::string info_method(const std::string& cmd) const; diff --git a/ccc/main.cc b/ccc/main.cc index 1d69fcb0c8b..fc176c1f5f0 100644 --- a/ccc/main.cc +++ b/ccc/main.cc @@ -1,20 +1,20 @@ /** -* Copyright 2022 Centreon -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* For more information : contact@centreon.com -*/ + * Copyright 2024 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ #include #include @@ -31,10 +31,13 @@ using namespace nlohmann; using namespace com::centreon::ccc; -static struct option long_options[] = { - {"version", no_argument, 0, 'v'}, {"help", no_argument, 0, 'h'}, - {"port", required_argument, 0, 'p'}, {"list", no_argument, 0, 'l'}, - {"nocolor", no_argument, 0, 'n'}, {0, 0, 0, 0}}; +static struct option long_options[] = {{"version", no_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {"port", required_argument, 0, 'p'}, + {"list", no_argument, 0, 'l'}, + {"nocolor", no_argument, 0, 'n'}, + {"full", no_argument, 0, 'F'}, + {0, 0, 0, 0}}; static void usage(bool color_enabled) { std::cout << color(color_enabled) @@ -56,6 +59,8 @@ static void usage(bool color_enabled) { " Displays the available methods.\n" " -n, --nocolor\n" " Outputs are displayed with the current color.\n" + " -F, --full\n" + " Forces display of fields containing default values.\n" "\n" << color(color_enabled) << "Examples:" << color(color_enabled) @@ -73,8 +78,9 @@ int main(int argc, char** argv) { bool list = false; bool help = false; bool color_enabled = true; + bool always_print_primitive_fields = false; - while ((opt = getopt_long(argc, argv, "vhnp:l", long_options, + while ((opt = getopt_long(argc, argv, "vhnp:lF", long_options, &option_index)) != -1) { switch (opt) { case 'v': @@ -97,6 +103,9 @@ int main(int argc, char** argv) { case 'l': list = true; break; + case 'F': + always_print_primitive_fields = true; + break; default: std::cerr << "Unrecognized argument '" << opt << "'" << std::endl; exit(3); @@ -118,7 +127,7 @@ int main(int argc, char** argv) { grpc::CreateChannel(url, grpc::InsecureChannelCredentials()); try { - client clt(channel, color_enabled); + client clt(channel, color_enabled, always_print_primitive_fields); if (help) { std::string message{clt.info_method(argv[optind])}; std::cout << "Input message for this function:\n" << message << std::endl; diff --git a/clib/CMakeLists.txt b/clib/CMakeLists.txt index b372208c48c..43b1af55ee0 100644 --- a/clib/CMakeLists.txt +++ b/clib/CMakeLists.txt @@ -143,7 +143,6 @@ include_directories("${INCLUDE_DIR}") # Add subdirectories. add_subdirectory(src/clib) -add_subdirectory(src/exceptions) add_subdirectory(src/logging) add_subdirectory(src/misc) add_subdirectory(src/io) @@ -154,7 +153,7 @@ endif() # Create shared library. add_library(centreon_clib SHARED ${SOURCES} ${HEADERS}) # Link target with required libraries. -target_link_libraries(centreon_clib ${LIB_THREAD} ${LIB_RT} ${LIB_DL}) +target_link_libraries(centreon_clib ${LIB_THREAD} ${LIB_RT} ${LIB_DL} fmt::fmt) # Set output name for the shared library. set_target_properties(centreon_clib PROPERTIES OUTPUT_NAME centreon_clib) # Install shared library. diff --git a/clib/inc/com/centreon/logging/backend.hh b/clib/inc/com/centreon/logging/backend.hh index 04a2aff3176..d9269c02964 100644 --- a/clib/inc/com/centreon/logging/backend.hh +++ b/clib/inc/com/centreon/logging/backend.hh @@ -20,14 +20,10 @@ #define CC_LOGGING_BACKEND_HH #include +#include -namespace com::centreon { +namespace com::centreon::logging { -namespace misc { -class stringifier; -} - -namespace logging { enum time_precision { none = 0, microsecond = 1, millisecond = 2, second = 3 }; /** @@ -64,7 +60,7 @@ class backend { virtual void show_thread_id(bool enable); protected: - void _build_header(misc::stringifier& buffer); + std::string _build_header(); bool _is_sync; mutable std::recursive_mutex _lock; @@ -75,8 +71,7 @@ class backend { protected: void _internal_copy(backend const& right); }; -} // namespace logging -} +} // namespace com::centreon::logging #endif // !CC_LOGGING_BACKEND_HH diff --git a/clib/inc/com/centreon/logging/temp_logger.hh b/clib/inc/com/centreon/logging/temp_logger.hh index d8f09e3fc13..8caff4b2017 100644 --- a/clib/inc/com/centreon/logging/temp_logger.hh +++ b/clib/inc/com/centreon/logging/temp_logger.hh @@ -19,7 +19,6 @@ #ifndef CC_LOGGING_TEMP_LOGGER_HH #define CC_LOGGING_TEMP_LOGGER_HH -#include #include "com/centreon/logging/engine.hh" #include "com/centreon/misc/stringifier.hh" diff --git a/clib/src/exceptions/CMakeLists.txt b/clib/src/exceptions/CMakeLists.txt deleted file mode 100644 index e39f758c56f..00000000000 --- a/clib/src/exceptions/CMakeLists.txt +++ /dev/null @@ -1,39 +0,0 @@ -## -## Copyright 2011-2014 Centreon -## -## Licensed under the Apache License, Version 2.0 (the "License"); -## you may not use this file except in compliance with the License. -## You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## -## For more information : contact@centreon.com -## - -# Set directories. -set(SRC_DIR "${SRC_DIR}/exceptions") -set(INC_DIR "${INC_DIR}/exceptions") - -# Set sources. -set( - SOURCES - ${SOURCES} - "${SRC_DIR}/basic.cc" - "${SRC_DIR}/interruption.cc" - PARENT_SCOPE -) - -# Set headers. -set( - HEADERS - ${HEADERS} - "${INC_DIR}/basic.hh" - "${INC_DIR}/interruption.hh" - PARENT_SCOPE -) diff --git a/clib/src/exceptions/basic.cc b/clib/src/exceptions/basic.cc deleted file mode 100644 index d5e33f54e82..00000000000 --- a/clib/src/exceptions/basic.cc +++ /dev/null @@ -1,88 +0,0 @@ -/** -* Copyright 2011-2014 Centreon -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* For more information : contact@centreon.com -*/ - -#include "com/centreon/exceptions/basic.hh" -#include -#include -#include "com/centreon/misc/stringifier.hh" - -using namespace com::centreon::exceptions; - -/** - * Default constructor. - */ -basic::basic() {} - -/** - * Constructor with debugging informations. - * - * @param[in] file The file from calling this object. - * @param[in] function The function from calling this object. - * @param[in] line The line from calling this object. - */ -basic::basic(char const* file, char const* function, int line) { - *this << "[" << file << ":" << line << "(" << function << ")] "; -} - -/** - * Copy constructor. - * - * @param[in] other Object to copy. - */ -basic::basic(basic const& other) : std::exception(other) { - _internal_copy(other); -} - -/** - * Destructor. - */ -basic::~basic() throw() {} - -/** - * Assignment operator. - * - * @param[in] other Object to copy. - * - * @return This object. - */ -basic& basic::operator=(basic const& other) { - if (this != &other) { - std::exception::operator=(other); - _internal_copy(other); - } - return (*this); -} - -/** - * Get the basic message. - * - * @return Basic message. - */ -char const* basic::what() const throw() { - return (_buffer.data()); -} - -/** - * Internal copy method. - * - * @param[in] other Object to copy. - */ -void basic::_internal_copy(basic const& other) { - _buffer = other._buffer; - return; -} diff --git a/clib/src/exceptions/interruption.cc b/clib/src/exceptions/interruption.cc deleted file mode 100644 index cace7f5657d..00000000000 --- a/clib/src/exceptions/interruption.cc +++ /dev/null @@ -1,60 +0,0 @@ -/** -* Copyright 2014 Centreon -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* For more information : contact@centreon.com -*/ - -#include "com/centreon/exceptions/interruption.hh" - -using namespace com::centreon::exceptions; - -/** - * Default constructor. - */ -interruption::interruption() {} - -/** - * Constructor with debugging informations. - * - * @param[in] file The file in which this object is created. - * @param[in] function The function creating this object. - * @param[in] line The line in the file creating this object. - */ -interruption::interruption(char const* file, char const* function, int line) - : basic(file, function, line) {} - -/** - * Copy constructor. - * - * @param[in] other Object to copy. - */ -interruption::interruption(interruption const& other) : basic(other) {} - -/** - * Destructor. - */ -interruption::~interruption() throw() {} - -/** - * Assignment operator. - * - * @param[in] other Object to copy. - * - * @return This object. - */ -interruption& interruption::operator=(interruption const& other) { - basic::operator=(other); - return (*this); -} diff --git a/clib/src/handle_manager.cc b/clib/src/handle_manager.cc index b8612f32703..dd95d861586 100644 --- a/clib/src/handle_manager.cc +++ b/clib/src/handle_manager.cc @@ -1,25 +1,25 @@ /** -* Copyright 2011-2013 Centreon -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* For more information : contact@centreon.com -*/ + * Copyright 2011-2013 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ #include "com/centreon/handle_manager.hh" #include #include -#include "com/centreon/exceptions/basic.hh" +#include "com/centreon/exceptions/msg_fmt.hh" #include "com/centreon/handle_action.hh" #include "com/centreon/handle_listener.hh" #include "com/centreon/task_manager.hh" @@ -59,15 +59,16 @@ handle_manager::~handle_manager() noexcept { void handle_manager::add(handle* h, handle_listener* hl, bool is_threadable) { // Check parameters. if (!h) - throw(basic_error() << "attempt to add null handle in handle manager"); + throw exceptions::msg_fmt("attempt to add null handle in handle manager"); if (!hl) - throw(basic_error() << "attempt to add null listener in handle manager"); + throw exceptions::msg_fmt("attempt to add null listener in handle manager"); // Check native handle. native_handle nh(h->get_native_handle()); if (nh == native_handle_null) - throw basic_error() << "attempt to add handle with invalid native " - "handle in the handle manager"; + throw exceptions::msg_fmt( + "attempt to add handle with invalid native handle in the handle " + "manager"); // Check that handle isn't already registered. if (_handles.find(nh) == _handles.end()) { @@ -76,8 +77,8 @@ void handle_manager::add(handle* h, handle_listener* hl, bool is_threadable) { _handles.insert(item); _recreate_array = true; } else - throw basic_error() << "attempt to add handle " - "already monitored by handle manager"; + throw exceptions::msg_fmt( + "attempt to add handle already monitored by handle manager"); } /** @@ -160,7 +161,7 @@ unsigned int handle_manager::remove(handle_listener* hl) { void handle_manager::multiplex() { // Check that task manager is present. if (!_task_manager) - throw basic_error() << "cannot multiplex handles with no task manager"; + throw exceptions::msg_fmt("cannot multiplex handles with no task manager"); // Create or update pollfd. _setup_array(); @@ -182,7 +183,7 @@ void handle_manager::multiplex() { int ret = _poll(_array, _handles.size(), timeout); if (ret == -1) { char const* msg(strerror(errno)); - throw basic_error() << "handle multiplexing failed: " << msg; + throw exceptions::msg_fmt("handle multiplexing failed: {}", msg); } // Dispatch events. diff --git a/clib/src/io/directory_entry.cc b/clib/src/io/directory_entry.cc index 2ba512978e9..b8aac418e45 100644 --- a/clib/src/io/directory_entry.cc +++ b/clib/src/io/directory_entry.cc @@ -1,20 +1,20 @@ /** -* Copyright 2012-2013 Centreon -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* For more information : contact@centreon.com -*/ + * Copyright 2012-2013 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ #include "com/centreon/io/directory_entry.hh" #include @@ -22,9 +22,10 @@ #include #include #include -#include "com/centreon/exceptions/basic.hh" +#include "com/centreon/exceptions/msg_fmt.hh" using namespace com::centreon::io; +using com::centreon::exceptions::msg_fmt; /** * Constructor. @@ -96,7 +97,7 @@ directory_entry::~directory_entry() noexcept {} std::string directory_entry::current_path() { char* buffer(getcwd(NULL, 0)); if (!buffer) - throw(basic_error() << "current path failed"); + throw msg_fmt("current path failed"); std::string path(buffer); free(buffer); return path; @@ -126,7 +127,7 @@ std::list const& directory_entry::entry_list( DIR* dir(opendir(_entry.path().c_str())); if (!dir) { char const* msg(strerror(errno)); - throw(basic_error() << "open directory failed: " << msg); + throw msg_fmt("open directory failed: {}", msg); } dirent entry; @@ -134,7 +135,7 @@ std::list const& directory_entry::entry_list( while (true) { if (readdir_r(dir, &entry, &result)) { closedir(dir); - throw(basic_error() << "parse directory failed"); + throw msg_fmt("parse directory failed"); } if (!result) break; diff --git a/clib/src/io/file_entry.cc b/clib/src/io/file_entry.cc index 0d0e6426873..3a3f3a0ac04 100644 --- a/clib/src/io/file_entry.cc +++ b/clib/src/io/file_entry.cc @@ -1,29 +1,30 @@ /** -* Copyright 2012-2013 Centreon -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* For more information : contact@centreon.com -*/ + * Copyright 2012-2013 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ #include "com/centreon/io/file_entry.hh" #include #include #include #include -#include "com/centreon/exceptions/basic.hh" +#include "com/centreon/exceptions/msg_fmt.hh" using namespace com::centreon::io; +using com::centreon::exceptions::msg_fmt; /** * Constructor. @@ -188,7 +189,7 @@ void file_entry::refresh() { memset(&_sbuf, 0, sizeof(_sbuf)); else if (stat(_path.c_str(), &_sbuf)) { char const* msg(strerror(errno)); - throw(basic_error() << "get file information failed: " << msg); + throw msg_fmt("get file information failed: {}", msg); } } diff --git a/clib/src/io/file_stream.cc b/clib/src/io/file_stream.cc index 9c1598226fc..16b65db4dcf 100644 --- a/clib/src/io/file_stream.cc +++ b/clib/src/io/file_stream.cc @@ -1,20 +1,20 @@ /** -* Copyright 2012-2013 Centreon -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* For more information : contact@centreon.com -*/ + * Copyright 2012-2013 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ #include "com/centreon/io/file_stream.hh" #include @@ -24,9 +24,10 @@ #include #include #include -#include "com/centreon/exceptions/basic.hh" +#include "com/centreon/exceptions/msg_fmt.hh" using namespace com::centreon::io; +using com::centreon::exceptions::msg_fmt; /************************************** * * @@ -108,7 +109,7 @@ bool file_stream::exists(std::string const& path) { void file_stream::flush() { if (fflush(_stream)) { char const* msg(strerror(errno)); - throw(basic_error() << "cannot flush stream: " << msg); + throw msg_fmt("cannot flush stream: {}", msg); } return; } @@ -126,9 +127,7 @@ com::centreon::native_handle file_stream::get_native_handle() { retval = fileno(_stream); if (retval < 0) { char const* msg(strerror(errno)); - throw(basic_error() << "could not get native handle from " - "file stream: " - << msg); + throw msg_fmt("could not get native handle from file stream: {}", msg); } } return retval; @@ -139,16 +138,16 @@ com::centreon::native_handle file_stream::get_native_handle() { */ void file_stream::open(char const* path, char const* mode) { if (!path) - throw(basic_error() << "invalid argument path: null pointer"); + throw msg_fmt("invalid argument path: null pointer"); if (!mode) - throw(basic_error() << "invalid argument mode: null pointer"); + throw msg_fmt("invalid argument mode: null pointer"); close(); _auto_close = true; _stream = fopen(path, mode); if (!_stream) { char const* msg(strerror(errno)); - throw(basic_error() << "could not open file '" << path << "': " << msg); + throw msg_fmt("could not open file '{}': {}", path, msg); } int fd(fileno(_stream)); int flags(0); @@ -182,14 +181,14 @@ void file_stream::open(std::string const& path, char const* mode) { */ unsigned long file_stream::read(void* data, unsigned long size) { if (!_stream) - throw(basic_error() << "attempt to read from closed file stream"); + throw msg_fmt("attempt to read from closed file stream"); if (!data || !size) - throw(basic_error() << "attempt to read from " - "file stream but do not except any result"); + throw msg_fmt( + "attempt to read from file stream but do not except any result"); ssize_t rb(::read(get_native_handle(), data, size)); if (rb < 0) { char const* msg(strerror(errno)); - throw(basic_error() << "could not read from file stream: " << msg); + throw msg_fmt("could not read from file stream: {}", msg); } return static_cast(rb); } @@ -264,20 +263,20 @@ unsigned long file_stream::size() { long original_offset(ftell(_stream)); if (-1 == original_offset) { char const* msg(strerror(errno)); - throw(basic_error() << "cannot tell position within file: " << msg); + throw msg_fmt("cannot tell position within file: {}", msg); } // Seek to end of file. if (fseek(_stream, 0, SEEK_END)) { char const* msg(strerror(errno)); - throw(basic_error() << "cannot seek to end of file: " << msg); + throw msg_fmt("cannot seek to end of file: {}", msg); } // Get position (size). long size(ftell(_stream)); if (size < 0) { char const* msg(strerror(errno)); - throw(basic_error() << "cannot get file size: " << msg); + throw msg_fmt("cannot get file size: {}", msg); } // Get back to original position. @@ -294,7 +293,7 @@ unsigned long file_stream::size() { char* file_stream::temp_path() { char* ret(::tmpnam(static_cast(NULL))); if (!ret) - throw basic_error() << "could not generate temporary file name"; + throw msg_fmt("could not generate temporary file name"); return ret; } @@ -308,13 +307,13 @@ char* file_stream::temp_path() { */ unsigned long file_stream::write(void const* data, unsigned long size) { if (!_stream) - throw(basic_error() << "attempt to write to a closed file stream"); + throw msg_fmt("attempt to write to a closed file stream"); if (!data || !size) - throw(basic_error() << "attempt to write no data to file stream"); + throw msg_fmt("attempt to write no data to file stream"); ssize_t wb(::write(get_native_handle(), data, size)); if (wb <= 0) { char const* msg(strerror(errno)); - throw(basic_error() << "could not write to file stream: " << msg); + throw msg_fmt("could not write to file stream: {}", msg); } return static_cast(wb); } diff --git a/clib/src/library.cc b/clib/src/library.cc index 218d44b989d..12c6389da75 100644 --- a/clib/src/library.cc +++ b/clib/src/library.cc @@ -1,24 +1,24 @@ /** -* Copyright 2011-2013 Centreon -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* For more information : contact@centreon.com -*/ + * Copyright 2011-2013 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ #include "com/centreon/library.hh" #include -#include "com/centreon/exceptions/basic.hh" +#include "com/centreon/exceptions/msg_fmt.hh" using namespace com::centreon; @@ -63,7 +63,7 @@ void library::load() { if (_handle) return; if (!(_handle = dlopen(_filename.c_str(), RTLD_LAZY | RTLD_GLOBAL))) - throw basic_error() << "load library failed: " << dlerror(); + throw exceptions::msg_fmt("load library failed: {}", dlerror()); } /** @@ -75,14 +75,14 @@ void library::load() { */ void* library::resolve(char const* symbol) { if (!_handle) - throw basic_error() << "could not find symbol '" << symbol - << "': library not loaded"; + throw exceptions::msg_fmt("could not find symbol '{}': library not loaded", + symbol); dlerror(); void* sym(dlsym(_handle, symbol)); if (!sym) { char const* msg(dlerror()); - throw basic_error() << "could not find symbol '" << symbol - << "': " << (msg ? msg : "unknown error"); + throw exceptions::msg_fmt("could not find symbol '{}': {}", symbol, + (msg ? msg : "unknown error")); } return sym; } @@ -128,6 +128,6 @@ void library::unload() { if (!_handle) return; if (dlclose(_handle)) - throw basic_error() << "unload library failed: " << dlerror(); + throw exceptions::msg_fmt("unload library failed: {}", dlerror()); _handle = nullptr; } diff --git a/clib/src/logging/backend.cc b/clib/src/logging/backend.cc index cdc7f17394b..bc6d92bd092 100644 --- a/clib/src/logging/backend.cc +++ b/clib/src/logging/backend.cc @@ -1,27 +1,28 @@ /** -* Copyright 2011-2013 Centreon -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* For more information : contact@centreon.com -*/ + * Copyright 2011-2013 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ #include "com/centreon/logging/backend.hh" +#include #include #include #include #include -#include "com/centreon/misc/stringifier.hh" +#include "com/centreon/exceptions/msg_fmt.hh" #include "com/centreon/timestamp.hh" using namespace com::centreon::logging; @@ -170,19 +171,21 @@ void backend::show_thread_id(bool enable) { * * @param[out] buffer The buffer to fill. */ -void backend::_build_header(misc::stringifier& buffer) { +std::string backend::_build_header() { // Build line header. + std::string buffer; if (_show_timestamp == second) - buffer << "[" << timestamp::now().to_seconds() << "] "; + buffer = fmt::format("[{}] ", timestamp::now().to_seconds()); else if (_show_timestamp == millisecond) - buffer << "[" << timestamp::now().to_mseconds() << "] "; + buffer = fmt::format("[{}] ", timestamp::now().to_mseconds()); else if (_show_timestamp == microsecond) - buffer << "[" << timestamp::now().to_useconds() << "] "; + buffer = fmt::format("[{}] ", timestamp::now().to_useconds()); if (_show_pid) { - buffer << "[" << getpid() << "] "; + buffer += fmt::format("[{}] ", getpid()); } if (_show_thread_id) - buffer << "[" << std::this_thread::get_id() << "] "; + buffer += fmt::format("[{}] ", std::this_thread::get_id()); + return buffer; } /** diff --git a/clib/src/logging/engine.cc b/clib/src/logging/engine.cc index ed0fec76573..bef9090ee9e 100644 --- a/clib/src/logging/engine.cc +++ b/clib/src/logging/engine.cc @@ -1,30 +1,31 @@ /** -* Copyright 2011-2013 Centreon -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* For more information : contact@centreon.com -*/ + * Copyright 2011-2013 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ #include "com/centreon/logging/engine.hh" #include #include #include #include -#include "com/centreon/exceptions/basic.hh" +#include "com/centreon/exceptions/msg_fmt.hh" #include "com/centreon/logging/backend.hh" using namespace com::centreon::logging; +using com::centreon::exceptions::msg_fmt; /** * Get the logger engine singleton. @@ -49,11 +50,11 @@ unsigned long engine::add(backend* obj, unsigned long long types, unsigned int verbose) { if (!obj) - throw(basic_error() << "add backend on the logging engine " - "failed: bad argument (null pointer)"); + throw msg_fmt( + "add backend on the logging engine failed: bad argument (null " + "pointer)"); if (verbose >= sizeof(unsigned int) * CHAR_BIT) - throw(basic_error() << "add backend on the logging engine " - "failed: invalid verbose"); + throw msg_fmt("add backend on the logging engine failed: invalid verbose"); std::unique_ptr info(new backend_info); info->obj = obj; @@ -125,8 +126,9 @@ bool engine::remove(unsigned long id) { */ unsigned int engine::remove(backend* obj) { if (!obj) - throw(basic_error() << "remove backend on the logging engine " - "failed:bad argument (null pointer)"); + throw msg_fmt( + "remove backend on the logging engine failed:bad argument (null " + "pointer)"); // Lock engine. std::lock_guard lock(_mtx); diff --git a/clib/src/logging/file.cc b/clib/src/logging/file.cc index 0c32d37f7dd..304d9afda26 100644 --- a/clib/src/logging/file.cc +++ b/clib/src/logging/file.cc @@ -1,29 +1,29 @@ /** -* Copyright 2011-2014 Centreon -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* For more information : contact@centreon.com -*/ + * Copyright 2011-2014 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ #include "com/centreon/logging/file.hh" #include #include #include -#include "com/centreon/exceptions/basic.hh" -#include "com/centreon/misc/stringifier.hh" +#include "com/centreon/exceptions/msg_fmt.hh" using namespace com::centreon::logging; +using com::centreon::exceptions::msg_fmt; /** * Default constructor. @@ -119,24 +119,22 @@ void file::log(uint64_t types, (void)verbose; (void)size; - misc::stringifier header; - _build_header(header); + std::string header = _build_header(); // Split msg by line. - misc::stringifier buffer; + std::string buffer; uint32_t i(0); uint32_t last(0); while (msg[i]) { if (msg[i] == '\n') { - buffer << header; - buffer.append(msg + last, i - last) << "\n"; + buffer += + fmt::format("{}{}\n", header, std::string(msg + last, i - last)); last = i + 1; } ++i; } if (last != i) { - buffer << header; - buffer.append(msg + last, i - last) << "\n"; + buffer += fmt::format("{}{}\n", header, std::string(msg + last, i - last)); } std::lock_guard lock(_lock); @@ -169,8 +167,7 @@ void file::open() { return; if (!(_out = fopen(_path.c_str(), "a"))) - throw(basic_error() << "failed to open file '" << _path - << "': " << strerror(errno)); + throw msg_fmt("failed to open file '{}': {}", _path, strerror(errno)); _size = ftell(_out); return; @@ -191,8 +188,7 @@ void file::reopen() { } while (ret == -1 && errno == EINTR); if (!(_out = fopen(_path.c_str(), "a"))) - throw(basic_error() << "failed to open file '" << _path - << "': " << strerror(errno)); + throw msg_fmt("failed to open file '{}': {}", _path, strerror(errno)); _size = ftell(_out); return; @@ -213,7 +209,6 @@ void file::_max_size_reached() { remove(_path.c_str()); if (!(_out = fopen(_path.c_str(), "a"))) - throw(basic_error() << "failed to open file '" << _path - << "': " << strerror(errno)); + throw msg_fmt("failed to open file '{}': {}", _path, strerror(errno)); _size = ftell(_out); } diff --git a/clib/src/logging/syslogger.cc b/clib/src/logging/syslogger.cc index 012b1c2a42a..b5a9a00d687 100644 --- a/clib/src/logging/syslogger.cc +++ b/clib/src/logging/syslogger.cc @@ -1,26 +1,25 @@ /** -* Copyright 2011-2013 Centreon -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* For more information : contact@centreon.com -*/ + * Copyright 2011-2013 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ #include "com/centreon/logging/syslogger.hh" #include #include -#include "com/centreon/exceptions/basic.hh" -#include "com/centreon/misc/stringifier.hh" +#include "com/centreon/exceptions/msg_fmt.hh" using namespace com::centreon::logging; @@ -78,11 +77,10 @@ void syslogger::log(uint64_t types, (void)verbose; (void)size; - misc::stringifier header; - _build_header(header); + std::string header = _build_header(); std::lock_guard lock(_lock); - syslog(LOG_ERR, "%s%s", header.data(), msg); + syslog(LOG_ERR, "%s%s", header.c_str(), msg); } /** diff --git a/clib/src/misc/command_line.cc b/clib/src/misc/command_line.cc index c84fea8cb9e..8cfe7f096a2 100644 --- a/clib/src/misc/command_line.cc +++ b/clib/src/misc/command_line.cc @@ -1,27 +1,28 @@ /** -* Copyright 2011-2013 Centreon -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* For more information : contact@centreon.com -*/ + * Copyright 2011-2013 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ #include "com/centreon/misc/command_line.hh" #include #include -#include "com/centreon/exceptions/basic.hh" +#include "com/centreon/exceptions/msg_fmt.hh" using namespace com::centreon::misc; +using com::centreon::exceptions::msg_fmt; /************************************** * * @@ -248,7 +249,7 @@ void command_line::parse(char const* cmdline, unsigned int size) { } if (state == e_decoding_in_quote) - throw(basic_error() << "missing separator '" << quote << "'"); + throw msg_fmt("missing separator '{}'", quote); // a last tokern if (state == e_decoding_field) { diff --git a/clib/src/misc/get_options.cc b/clib/src/misc/get_options.cc index 552a0b708ff..8031f354a6e 100644 --- a/clib/src/misc/get_options.cc +++ b/clib/src/misc/get_options.cc @@ -21,9 +21,10 @@ #include #include #include -#include "com/centreon/exceptions/basic.hh" +#include "com/centreon/exceptions/msg_fmt.hh" using namespace com::centreon::misc; +using com::centreon::exceptions::msg_fmt; /** * Default constructor. @@ -94,7 +95,7 @@ std::map const& get_options::get_arguments() const noexcept { argument& get_options::get_argument(char name) { std::map::iterator it(_arguments.find(name)); if (it == _arguments.end()) - throw(basic_error() << "argument '" << name << "' not found"); + throw msg_fmt("argument \"{}\" not found", name); return it->second; } @@ -108,7 +109,7 @@ argument& get_options::get_argument(char name) { argument const& get_options::get_argument(char name) const { std::map::const_iterator it(_arguments.find(name)); if (it != _arguments.end()) - throw(basic_error() << "argument '" << name << "' not found"); + throw msg_fmt("argument \"{}\" not found", name); return it->second; } @@ -126,7 +127,7 @@ argument& get_options::get_argument(std::string const& long_name) { it != end; ++it) if (it->second.get_long_name() == long_name) return it->second; - throw(basic_error() << "argument \"" << long_name << "\" not found"); + throw msg_fmt("argument \"{}\" not found", long_name); } /** @@ -143,7 +144,7 @@ argument const& get_options::get_argument(std::string const& long_name) const { it != end; ++it) if (it->second.get_long_name() != long_name) return it->second; - throw(basic_error() << "argument \"" << long_name << "\" not found"); + throw msg_fmt("argument \"{}\" not found", long_name); } /** @@ -268,9 +269,9 @@ void get_options::_parse_arguments(std::vector const& args) { arg = &get_argument(key[0]); } else break; - } catch (std::exception const& e) { + } catch (const std::exception& e) { (void)e; - throw(basic_error() << "unrecognized option '" << key << "'"); + throw msg_fmt("unrecognized option '{}'", key); } arg->set_is_set(true); @@ -278,7 +279,7 @@ void get_options::_parse_arguments(std::vector const& args) { if (has_value) arg->set_value(value); else if (++it == end) - throw(basic_error() << "option '" << key << "' requires an argument"); + throw msg_fmt("option '{}' requires an argument", key); else arg->set_value(*it); } diff --git a/clib/src/process.cc b/clib/src/process.cc index cf0475c5b67..8d5814e055a 100644 --- a/clib/src/process.cc +++ b/clib/src/process.cc @@ -1,20 +1,20 @@ /** -* Copyright 2012-2013,2020-2021 Centreon -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* For more information : contact@centreon.com -*/ + * Copyright 2012-2013,2020-2021 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ #include @@ -31,12 +31,13 @@ #include #include #include -#include "com/centreon/exceptions/interruption.hh" +#include "com/centreon/exceptions/msg_fmt.hh" #include "com/centreon/misc/command_line.hh" #include "com/centreon/process_listener.hh" #include "com/centreon/process_manager.hh" using namespace com::centreon; +using com::centreon::exceptions::msg_fmt; // environ is not declared on *BSD. extern char** environ; @@ -105,8 +106,8 @@ void process::exec(char const* cmd, char** env, uint32_t timeout) { // Check if process already running. if (_is_running()) - throw basic_error() << "process " << _process - << " is already started and has not been waited"; + throw msg_fmt("process {} is already started and has not been waited", + _process); // Reset variable. _buffer_err.clear(); @@ -453,10 +454,10 @@ unsigned int process::write(void const* data, unsigned int size) { if (wb < 0) { char const* msg(strerror(errno)); if (errno == EINTR) - throw interruption_error() << msg; - throw basic_error() << "could not write '" - << to_string(static_cast(data), size) - << "' on process " << my_process << "'s input: " << msg; + throw msg_fmt("{}", msg); + throw msg_fmt("could not write '{}' on process {}'s input: {}", + to_string(static_cast(data), size), my_process, + msg); } return wb; } @@ -500,33 +501,29 @@ pid_t process::_create_process_with_setpgid(char* const* args, char** env) { posix_spawnattr_t attr; int ret = posix_spawnattr_init(&attr); if (ret) - throw basic_error() << "cannot initialize spawn attributes: " - << strerror(ret); + throw msg_fmt("cannot initialize spawn attributes: {}", strerror(ret)); ret = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETPGROUP); if (ret) { posix_spawnattr_destroy(&attr); - throw basic_error() << "cannot set spawn flag: " << strerror(ret); + throw msg_fmt("cannot set spawn flag: {}", strerror(ret)); } ret = posix_spawnattr_setpgroup(&attr, 0); if (ret) { posix_spawnattr_destroy(&attr); - throw basic_error() - << "cannot set process group ID of to-be-spawned process: " - << strerror(ret); + throw msg_fmt("cannot set process group ID of to-be-spawned process: {}", + strerror(ret)); } if (posix_spawnp(&pid, args[0], NULL, &attr, args, env)) { char const* msg(strerror(errno)); posix_spawnattr_destroy(&attr); - throw basic_error() << "could not create process '" << args[0] - << "': " << msg; + throw msg_fmt("could not create process '{}': {}", args[0], msg); } posix_spawnattr_destroy(&attr); #else pid = fork(); if (pid == static_cast(-1)) { char const* msg(strerror(errno)); - throw basic_error() << "could not create process '" << args[0] - << "': " << msg; + throw msg_fmt("could not create process '{}': {}", args[0], msg); } // Child execution. @@ -546,15 +543,13 @@ pid_t process::_create_process_without_setpgid(char* const* args, char** env) { #ifdef HAVE_SPAWN_H if (posix_spawnp(&pid, args[0], NULL, NULL, args, env)) { char const* msg(strerror(errno)); - throw basic_error() << "could not create process '" << args[0] - << "': " << msg; + throw msg_fmt("could not create process '{}': {}", args[0], msg); } #else pid = vfork(); if (pid == static_cast(-1)) { char const* msg(strerror(errno)); - throw basic_error() << "could not create process '" << args[0] - << "': " << msg; + throw msg_fmt("could not create process '{}': {}", args[0], msg); } // Child execution. @@ -576,7 +571,7 @@ void process::_dev_null(int fd, int flags) { int newfd(::open("/dev/null", flags)); if (newfd < 0) { char const* msg(strerror(errno)); - throw basic_error() << "could not open /dev/null: " << msg; + throw msg_fmt("could not open /dev/null: {}", msg); } try { _dup2(newfd, fd); @@ -600,7 +595,7 @@ int process::_dup(int oldfd) { if (errno == EINTR) continue; char const* msg(strerror(errno)); - throw basic_error() << "could not duplicate FD: " << msg; + throw msg_fmt("could not duplicate FD: {}", msg); } return newfd; } @@ -616,7 +611,7 @@ void process::_dup2(int oldfd, int newfd) { if (errno == EINTR) continue; char const* msg(strerror(errno)); - throw basic_error() << "could not duplicate FD: " << msg; + throw msg_fmt("could not duplicate FD: {}", msg); } } @@ -629,8 +624,7 @@ void process::_kill(int sig) { if (_process && _process != static_cast(-1)) { if (::kill(_process, sig) != 0) { char const* msg(strerror(errno)); - throw basic_error() << "could not terminate process " << _process << ": " - << msg; + throw msg_fmt("could not terminate process {}: {}", _process, msg); } } } @@ -643,7 +637,7 @@ void process::_kill(int sig) { void process::_pipe(int fds[2]) { if (pipe(fds) != 0) { char const* msg(strerror(errno)); - throw basic_error() << "pipe creation failed: " << msg; + throw msg_fmt("pipe creation failed: {}", msg); } } @@ -655,9 +649,8 @@ ssize_t process::do_read(int fd) { if (size == -1) { char const* msg(strerror(errno)); if (errno == EINTR) - throw interruption_error() << msg; - throw basic_error() << "could not read from process " << _process << ": " - << msg; + throw msg_fmt("{}", msg); + throw msg_fmt("could not read from process {}: {}", _process, msg); } if (size == 0) return 0; @@ -698,13 +691,12 @@ void process::_set_cloexec(int fd) { if (errno == EINTR) continue; char const* msg(strerror(errno)); - throw basic_error() << "Could not get file descriptor flags: " << msg; + throw msg_fmt("Could not get file descriptor flags: {}", msg); } while (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) { if (errno == EINTR) continue; - throw basic_error() << "Could not set close-on-exec flag: " - << strerror(errno); + throw msg_fmt("Could not set close-on-exec flag: {}", strerror(errno)); } } diff --git a/clib/src/process_manager.cc b/clib/src/process_manager.cc index a0a4515830d..a492709bac6 100644 --- a/clib/src/process_manager.cc +++ b/clib/src/process_manager.cc @@ -1,20 +1,20 @@ /** -* Copyright 2012-2013, 2021 Centreon -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* For more information : contact@centreon.com -*/ + * Copyright 2012-2013, 2021 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ #include "com/centreon/process_manager.hh" #include @@ -24,7 +24,7 @@ #include #include #include -#include "com/centreon/exceptions/basic.hh" +#include "com/centreon/exceptions/msg_fmt.hh" #include "com/centreon/logging/logger.hh" #include "com/centreon/process_listener.hh" @@ -190,7 +190,7 @@ void process_manager::_close_stream(int fd) noexcept { _update = true; std::unordered_map::iterator it(_processes_fd.find(fd)); if (it == _processes_fd.end()) - throw basic_error() << "invalid fd: not found in processes fd list"; + throw exceptions::msg_fmt("invalid fd: not found in processes fd list"); process* p = it->second; _processes_fd.erase(it); @@ -258,7 +258,7 @@ uint32_t process_manager::_read_stream(int fd) noexcept { auto it = _processes_fd.find(fd); if (it == _processes_fd.end()) { _update = true; - throw basic_error() << "invalid fd: not found in processes fd list"; + throw exceptions::msg_fmt("invalid fd: not found in processes fd list"); } p = it->second; } @@ -307,7 +307,7 @@ void process_manager::_run() { ret = 0; else { const char* msg = strerror(errno); - throw basic_error() << "poll failed: " << msg; + throw exceptions::msg_fmt("poll failed: {}", msg); } } for (uint32_t i = 0, checked = 0; diff --git a/clib/test/CMakeLists.txt b/clib/test/CMakeLists.txt index 49e2611572e..872febd0e60 100644 --- a/clib/test/CMakeLists.txt +++ b/clib/test/CMakeLists.txt @@ -20,7 +20,6 @@ include_directories(${PROJECT_SOURCE_DIR}/test/) add_executable(ut_clib ${PROJECT_SOURCE_DIR}/test/process.cc - ${PROJECT_SOURCE_DIR}/test/exceptions.cc ${PROJECT_SOURCE_DIR}/test/handle_manager.cc ${PROJECT_SOURCE_DIR}/test/io.cc ${PROJECT_SOURCE_DIR}/test/library.cc diff --git a/clib/test/backend_test.hh b/clib/test/backend_test.hh index dee61676bb0..3ebeb1446e3 100644 --- a/clib/test/backend_test.hh +++ b/clib/test/backend_test.hh @@ -20,7 +20,6 @@ #define CC_TEST_LOGGING_BACKEND_TEST_HH #include "com/centreon/logging/backend.hh" -#include "com/centreon/misc/stringifier.hh" namespace com::centreon { @@ -49,9 +48,7 @@ class backend_test : public backend { (void)types; (void)verbose; - misc::stringifier header; - _build_header(header); - _buffer.append(header.data(), header.size()); + _buffer = _build_header(); _buffer.append(msg, size); ++_nb_call; } @@ -66,6 +63,6 @@ class backend_test : public backend { }; } // namespace logging -} +} // namespace com::centreon #endif // !CC_TEST_LOGGING_BACKEND_TEST_HH diff --git a/clib/test/exceptions.cc b/clib/test/exceptions.cc deleted file mode 100644 index 3bade486092..00000000000 --- a/clib/test/exceptions.cc +++ /dev/null @@ -1,122 +0,0 @@ -/** - * Copyright 2020 Centreon (https://www.centreon.com/) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * For more information : contact@centreon.com - * - */ -#include -#include -#include -#include "com/centreon/exceptions/basic.hh" - -using namespace com::centreon::exceptions; - -TEST(ClibException, BasicCtor) { - const unsigned int line = __LINE__; - - basic ex1(__FILE__, __func__, line); // __func__ <-- FUNCTION - - std::ostringstream oss; - oss << "[" << __FILE__ << ":" << line << "(" << __func__ - << ")] "; // __func__ <-- FUNCTION - ASSERT_STREQ(ex1.what(), oss.str().c_str()); -} - -TEST(ClibException, BasicCopy) { - static char const message[] = "Centreon Clib"; - const unsigned int line = __LINE__; - - basic ex(__FILE__, __func__, line); // __func__ <-- FUNCTION - ex << message; - - std::ostringstream oss; - oss << "[" << __FILE__ << ":" << line << "(" << __func__ << ")] " << message; - ASSERT_STREQ(ex.what(), oss.str().c_str()); -} - -TEST(ClibException, BasicInsertChar) { - basic ex; - ex << static_cast(CHAR_MIN); - ex << static_cast(CHAR_MAX); - - char ref[] = {CHAR_MIN, CHAR_MAX, 0}; - ASSERT_STREQ(ex.what(), ref); -} - -TEST(ClibException, BasicInsertInt) { - basic ex; - ex << static_cast(INT_MIN); - ex << static_cast(INT_MAX); - - std::ostringstream oss; - oss << INT_MIN << INT_MAX; - ASSERT_STREQ(ex.what(), oss.str().c_str()); -} - -TEST(ClibException, BasicInsertLong) { - basic ex; - ex << static_cast(LONG_MIN); - ex << static_cast(LONG_MAX); - - std::ostringstream oss; - oss << LONG_MIN << LONG_MAX; - ASSERT_STREQ(ex.what(), oss.str().c_str()); -} - -TEST(ClibException, BasicInsertLongLong) { - basic ex; - ex << static_cast(LLONG_MIN); - ex << static_cast(LLONG_MAX); - - std::ostringstream oss; - oss << LLONG_MIN << LLONG_MAX; - ASSERT_STREQ(ex.what(), oss.str().c_str()); -} - -TEST(ClibException, BasicInsertPChar) { - basic ex; - ex << __FILE__; - ASSERT_STREQ(ex.what(), __FILE__); -} - -TEST(ClibException, BasicInsertUInt) { - basic ex; - ex << static_cast(0); - ex << static_cast(UINT_MAX); - - std::ostringstream oss; - oss << 0 << UINT_MAX; - ASSERT_STREQ(ex.what(), oss.str().c_str()); -} - -TEST(ClibException, BasicInsertULong) { - basic ex; - ex << static_cast(0); - ex << static_cast(ULONG_MAX); - - std::ostringstream oss; - oss << 0 << ULONG_MAX; - ASSERT_STREQ(ex.what(), oss.str().c_str()); -} - -TEST(ClibException, BasicInsertULongLong) { - basic ex; - ex << static_cast(0); - ex << static_cast(ULLONG_MAX); - - std::ostringstream oss; - oss << 0 << ULLONG_MAX; - ASSERT_STREQ(ex.what(), oss.str().c_str()); -} diff --git a/clib/test/io.cc b/clib/test/io.cc index 84505fc06a1..eb93c0b3dda 100644 --- a/clib/test/io.cc +++ b/clib/test/io.cc @@ -18,7 +18,7 @@ */ #include #include -#include "com/centreon/exceptions/basic.hh" +#include "com/centreon/exceptions/msg_fmt.hh" #include "com/centreon/io/directory_entry.hh" #include "com/centreon/io/file_stream.hh" @@ -196,7 +196,7 @@ TEST(ClibIO, FileStreamRead) { try { tmp_file_stream.read(NULL, 1); retval = 1; - } catch (exceptions::basic const& e) { + } catch (const exceptions::msg_fmt& e) { (void)e; } // Real read. @@ -253,7 +253,7 @@ TEST(ClibIO, FileStreamWrite) { tmp_file_stream.open(tmp_file_name, "w"); // NULL write. - ASSERT_THROW(tmp_file_stream.write(NULL, 1), exceptions::basic); + ASSERT_THROW(tmp_file_stream.write(NULL, 1), exceptions::msg_fmt); // Real write. char const* data("some data"); diff --git a/clib/test/library.cc b/clib/test/library.cc index 9379f72a4d1..5a98ea06c62 100644 --- a/clib/test/library.cc +++ b/clib/test/library.cc @@ -19,7 +19,7 @@ #include "com/centreon/library.hh" #include #include -#include "com/centreon/exceptions/basic.hh" +#include "com/centreon/exceptions/msg_fmt.hh" using namespace com::centreon; using namespace com::centreon::exceptions; @@ -28,17 +28,17 @@ void load_library_success() { // create library object. library lib("./tests/libshared_testing_library.so"); if (lib.is_loaded()) - throw(basic_error() << "constructor failed"); + throw msg_fmt("constructor failed"); // load library. lib.load(); if (!lib.is_loaded()) - throw(basic_error() << "load failed"); + throw msg_fmt("load failed"); // unload library. lib.unload(); if (lib.is_loaded()) - throw(basic_error() << "unload failed"); + throw msg_fmt("unload failed"); } void load_library_failed() { @@ -46,8 +46,8 @@ void load_library_failed() { // create library object. library lib("libnot_found.so"); lib.load(); - throw(basic_error() << "load failed: lib dosn't exist"); - } catch (std::exception const& e) { + throw msg_fmt("load failed: lib dosn't exist"); + } catch (const std::exception& e) { (void)e; } } diff --git a/clib/test/process.cc b/clib/test/process.cc index 7ea60935165..dfe9143cca5 100644 --- a/clib/test/process.cc +++ b/clib/test/process.cc @@ -22,7 +22,7 @@ #include #include #include "com/centreon/clib.hh" -#include "com/centreon/exceptions/basic.hh" +#include "com/centreon/exceptions/msg_fmt.hh" using namespace com::centreon; diff --git a/clib/test/task_manager.cc b/clib/test/task_manager.cc index 9a8411a6008..e607d016a03 100644 --- a/clib/test/task_manager.cc +++ b/clib/test/task_manager.cc @@ -19,7 +19,7 @@ #include "com/centreon/task_manager.hh" #include #include -#include "com/centreon/exceptions/basic.hh" +#include "com/centreon/exceptions/msg_fmt.hh" // Global task manager. using namespace com::centreon; diff --git a/cmake-vcpkg.sh b/cmake-vcpkg.sh index 96f76b4de32..47ec425bc50 100755 --- a/cmake-vcpkg.sh +++ b/cmake-vcpkg.sh @@ -104,6 +104,9 @@ if [ -r /etc/centos-release -o -r /etc/almalinux-release ] ; then elif [[ "$maj" == "centos7" ]] ; then yum -y install epel-release cmake3 cmake='cmake3' + elif [[ "$maj" == "centos9" ]] ; then + dnf config-manager --set-enabled crb + dnf -y install epel-release else dnf -y install cmake cmake='cmake' @@ -145,6 +148,7 @@ if [ -r /etc/centos-release -o -r /etc/almalinux-release ] ; then openssl-devel libssh2-devel libcurl-devel + tar zlib-devel ) if [[ "$maj" == 'centos8' ]] ; then diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 6a8cb3b5bc7..5ec51626812 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -64,7 +64,10 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") else() # we need not many things to just compile centreon-monitoring-agent # (centagent) - set(SOURCES ${SRC_DIR}/perfdata.cc ${SRC_DIR}/utf8.cc) + set(SOURCES + ${SRC_DIR}/perfdata.cc + ${SRC_DIR}/rapidjson_helper.cc + ${SRC_DIR}/utf8.cc) endif() # Include directories. diff --git a/common/engine_conf/host_helper.cc b/common/engine_conf/host_helper.cc index 2841618b9e9..b0fc2a5fd14 100644 --- a/common/engine_conf/host_helper.cc +++ b/common/engine_conf/host_helper.cc @@ -66,7 +66,15 @@ bool host_helper::hook(std::string_view key, const std::string_view& value) { /* Since we use key to get back the good key value, it is faster to give key * by copy to the method. We avoid one key allocation... */ key = validate_key(key); - if (key == "contactgroups") { + if (key == "host_name") { + obj->set_host_name(std::string(value)); + set_changed(obj->descriptor()->FindFieldByName("host_name")->index()); + if (obj->alias().empty()) { + obj->set_alias(std::string(value)); + set_changed(obj->descriptor()->FindFieldByName("alias")->index()); + } + return true; + } else if (key == "contactgroups") { fill_string_group(obj->mutable_contactgroups(), value); return true; } else if (key == "contacts") { diff --git a/common/engine_conf/state_helper.hh b/common/engine_conf/state_helper.hh index ae3a4a172ea..112fab8ac22 100644 --- a/common/engine_conf/state_helper.hh +++ b/common/engine_conf/state_helper.hh @@ -23,7 +23,6 @@ #include #include "common/engine_conf/message_helper.hh" -#include "common/engine_conf/state.pb.h" namespace com::centreon::engine::configuration { diff --git a/common/engine_legacy_conf/host.cc b/common/engine_legacy_conf/host.cc index 7ceb1bc7a69..e64abf9e8f6 100644 --- a/common/engine_legacy_conf/host.cc +++ b/common/engine_legacy_conf/host.cc @@ -1348,6 +1348,9 @@ bool host::_set_host_id(uint64_t value) { */ bool host::_set_host_name(std::string const& value) { _host_name = value; + // if alias is empty we take the host name, better than taking template alias + if (_alias.empty()) + _alias = value; return true; } diff --git a/common/process/CMakeLists.txt b/common/process/CMakeLists.txt index f79bbaaa657..22235468ac6 100644 --- a/common/process/CMakeLists.txt +++ b/common/process/CMakeLists.txt @@ -27,4 +27,8 @@ add_library( target_precompile_headers(centreon_process REUSE_FROM centreon_common) +if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + target_link_libraries(centreon_process INTERFACE Boost::process) +endif() + set_property(TARGET centreon_process PROPERTY POSITION_INDEPENDENT_CODE ON) diff --git a/common/tests/CMakeLists.txt b/common/tests/CMakeLists.txt index d44100b1313..bfc0cbbff4c 100644 --- a/common/tests/CMakeLists.txt +++ b/common/tests/CMakeLists.txt @@ -33,6 +33,7 @@ else() add_executable(ut_common perfdata_test.cc process_test.cc + rapidjson_helper_test.cc test_main_win.cc utf8_test.cc ${TESTS_SOURCES}) diff --git a/common/tests/rapidjson_helper_test.cc b/common/tests/rapidjson_helper_test.cc index 384db3424d1..b88afa599f9 100644 --- a/common/tests/rapidjson_helper_test.cc +++ b/common/tests/rapidjson_helper_test.cc @@ -30,26 +30,32 @@ using namespace com::centreon; using namespace com::centreon::common; +#ifdef _WINDOWS +#define JSON_FILE_PATH "C:/Users/Public/toto.json" +#else +#define JSON_FILE_PATH "/tmp/toto.json" +#endif + TEST(rapidjson_helper_test, unknown_file) { - ::unlink("/tmp/toto.json"); - ASSERT_THROW(rapidjson_helper::read_from_file("/tmp/toto.json"), + ::unlink(JSON_FILE_PATH); + ASSERT_THROW(rapidjson_helper::read_from_file(JSON_FILE_PATH), exceptions::msg_fmt); } TEST(rapidjson_helper_test, bad_file) { - ::unlink("/tmp/toto.json"); + ::unlink(JSON_FILE_PATH); - std::ofstream oss("/tmp/toto.json"); + std::ofstream oss(JSON_FILE_PATH); oss << "fkjsdgheirgiergegeg"; oss.close(); - ASSERT_THROW(rapidjson_helper::read_from_file("/tmp/toto.json"), + ASSERT_THROW(rapidjson_helper::read_from_file(JSON_FILE_PATH), exceptions::msg_fmt); } TEST(rapidjson_helper_test, good_file) { - ::unlink("/tmp/toto.json"); + ::unlink(JSON_FILE_PATH); - std::ofstream oss("/tmp/toto.json"); + std::ofstream oss(JSON_FILE_PATH); oss << R"( { "int_val":5, @@ -61,7 +67,7 @@ TEST(rapidjson_helper_test, good_file) { } )"; oss.close(); - auto json_doc = rapidjson_helper::read_from_file("/tmp/toto.json"); + auto json_doc = rapidjson_helper::read_from_file(JSON_FILE_PATH); rapidjson_helper test(json_doc); ASSERT_EQ(5, test.get_int("int_val")); @@ -73,16 +79,16 @@ TEST(rapidjson_helper_test, good_file) { } TEST(rapidjson_helper_test, bad_array) { - ::unlink("/tmp/toto.json"); + ::unlink(JSON_FILE_PATH); - std::ofstream oss("/tmp/toto.json"); + std::ofstream oss(JSON_FILE_PATH); oss << R"( { "toto": 5 } )"; oss.close(); - auto json_doc = rapidjson_helper::read_from_file("/tmp/toto.json"); + auto json_doc = rapidjson_helper::read_from_file(JSON_FILE_PATH); rapidjson_helper test(json_doc); ASSERT_THROW(test.begin(), exceptions::msg_fmt); } diff --git a/connectors/common/src/parser.cc b/connectors/common/src/parser.cc index 027ae6740d1..b0be50d7303 100644 --- a/connectors/common/src/parser.cc +++ b/connectors/common/src/parser.cc @@ -1,27 +1,28 @@ /** -* Copyright 2011-2014 Centreon -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* For more information : contact@centreon.com -*/ + * Copyright 2011-2014 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ #include "com/centreon/connector/parser.hh" #include "com/centreon/connector/ipolicy.hh" #include "com/centreon/connector/log.hh" -#include "com/centreon/exceptions/basic.hh" +#include "com/centreon/exceptions/msg_fmt.hh" using namespace com::centreon::connector; +using com::centreon::exceptions::msg_fmt; parser::parser(const shared_io_context& io_context, const std::shared_ptr& policy) @@ -145,6 +146,6 @@ void parser::_parse(std::string const& cmd) { _dont_care_about_stdin_eof = true; break; default: - throw basic_error() << "invalid command received (ID " << id << ")"; + throw msg_fmt("invalid command received (ID {})", id); }; } diff --git a/connectors/perl/src/embedded_perl.cc b/connectors/perl/src/embedded_perl.cc index c466b4a8f89..9bcee214cec 100644 --- a/connectors/perl/src/embedded_perl.cc +++ b/connectors/perl/src/embedded_perl.cc @@ -1,25 +1,25 @@ /** -* Copyright 2022 Centreon -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* For more information : contact@centreon.com -*/ + * Copyright 2022 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ #include "com/centreon/connector/perl/embedded_perl.hh" #include "com/centreon/connector/log.hh" #include "com/centreon/connector/perl/checks/check.hh" -#include "com/centreon/exceptions/basic.hh" +#include "com/centreon/exceptions/msg_fmt.hh" #include @@ -96,8 +96,8 @@ pid_t embedded_perl::run(std::string const& cmd, const shared_io_context& io_context) { // Check arguments. if (!fds) - throw basic_error() << "cannot run Perl script without " - "fetching process' descriptors"; + throw exceptions::msg_fmt( + "cannot run Perl script without fetching process' descriptors"); // Extract arguments. size_t pos(cmd.find(' ')); @@ -126,12 +126,12 @@ pid_t embedded_perl::run(std::string const& cmd, argv[2] = nullptr; if (call_argv("Embed::Persistent::eval_file", G_EVAL | G_SCALAR, (char**)argv) != 1) - throw basic_error() << "could not compile Perl script " << file; + throw exceptions::msg_fmt("could not compile Perl script {}", file); } SPAGAIN; handle = POPs; if (SvTRUE(ERRSV)) - throw basic_error() << "Embedded Perl error: " << SvPV_nolen(ERRSV); + throw exceptions::msg_fmt("Embedded Perl error: {}", SvPV_nolen(ERRSV)); // Insert in parsed file list. _parsed.insert(std::make_pair(file, handle)); @@ -146,12 +146,12 @@ pid_t embedded_perl::run(std::string const& cmd, int out_pipe[2]; if (pipe(in_pipe)) { char const* msg(strerror(errno)); - throw basic_error() << msg; + throw exceptions::msg_fmt("{}", msg); } else if (pipe(err_pipe)) { char const* msg(strerror(errno)); close(in_pipe[0]); close(in_pipe[1]); - throw basic_error() << msg; + throw exceptions::msg_fmt("{}", msg); } if (pipe(out_pipe)) { char const* msg(strerror(errno)); @@ -159,7 +159,7 @@ pid_t embedded_perl::run(std::string const& cmd, close(in_pipe[1]); close(err_pipe[0]); close(err_pipe[1]); - throw basic_error() << msg; + throw exceptions::msg_fmt("{}", msg); } io_context->notify_fork(asio::io_context::fork_prepare); @@ -245,7 +245,7 @@ pid_t embedded_perl::run(std::string const& cmd, close(out_pipe[1]); close(err_pipe[0]); close(err_pipe[1]); - throw basic_error() << msg; + throw exceptions::msg_fmt("{}", msg); } return child; @@ -288,7 +288,7 @@ embedded_perl::embedded_perl([[maybe_unused]] int argc, int script_fd(mkstemp(script_path)); if (script_fd < 0) { char const* msg(strerror(errno)); - throw basic_error() << "could not create temporary file: " << msg; + throw exceptions::msg_fmt("could not create temporary file: {}", msg); } log::core()->info("temporary script path is {}", script_path); @@ -309,7 +309,7 @@ embedded_perl::embedded_perl([[maybe_unused]] int argc, char const* msg(strerror(errno)); close(script_fd); unlink(script_path); - throw basic_error() << "could not write embedded script: " << msg; + throw exceptions::msg_fmt("could not write embedded script: {}", msg); } len -= wb; data += wb; @@ -324,7 +324,7 @@ embedded_perl::embedded_perl([[maybe_unused]] int argc, if (!(my_perl = perl_alloc())) { log::core()->error("could not allocate Perl interpreter"); - throw basic_error() << "could not allocate Perl interpreter"; + throw exceptions::msg_fmt("could not allocate Perl interpreter"); } perl_construct(my_perl); PL_origalen = 1; @@ -337,7 +337,7 @@ embedded_perl::embedded_perl([[maybe_unused]] int argc, if (perl_parse(my_perl, &xs_init, sizeof(embedding) / sizeof(*embedding), (char**)embedding, nullptr)) { log::core()->error("could not parse embedded Perl script"); - throw basic_error() << "could not parse embedded Perl script"; + throw exceptions::msg_fmt("could not parse embedded Perl script"); } PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_run(my_perl); diff --git a/connectors/perl/src/main.cc b/connectors/perl/src/main.cc index 62b5110e336..9652f3ac6ef 100644 --- a/connectors/perl/src/main.cc +++ b/connectors/perl/src/main.cc @@ -1,26 +1,26 @@ /** -* Copyright 2022 Centreon -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* For more information : contact@centreon.com -*/ + * Copyright 2022 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ #include "com/centreon/connector/log.hh" #include "com/centreon/connector/perl/embedded_perl.hh" #include "com/centreon/connector/perl/options.hh" #include "com/centreon/connector/perl/policy.hh" -#include "com/centreon/exceptions/basic.hh" +#include "com/centreon/exceptions/msg_fmt.hh" using namespace com::centreon; using namespace com::centreon::connector; @@ -50,7 +50,7 @@ int main(int argc, char** argv, char** env) { try { opts.parse(argc - 1, argv + 1); - } catch (exceptions::basic const& e) { + } catch (const exceptions::msg_fmt& e) { std::cout << e.what() << std::endl << opts.usage() << std::endl; return EXIT_FAILURE; } @@ -108,7 +108,7 @@ int main(int argc, char** argv, char** env) { io_context->run(); } - } catch (std::exception const& e) { + } catch (const std::exception& e) { log::core()->error(e.what()); } diff --git a/connectors/perl/src/orders/parser.cc b/connectors/perl/src/orders/parser.cc index f487c866863..d95b76fa371 100644 --- a/connectors/perl/src/orders/parser.cc +++ b/connectors/perl/src/orders/parser.cc @@ -1,27 +1,28 @@ /** -* Copyright 2011-2013 Centreon -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* For more information : contact@centreon.com -*/ + * Copyright 2011-2013 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ #include "com/centreon/connector/perl/orders/parser.hh" #include "com/centreon/connector/ipolicy.hh" #include "com/centreon/connector/log.hh" -#include "com/centreon/exceptions/basic.hh" +#include "com/centreon/exceptions/msg_fmt.hh" using namespace com::centreon::connector::perl::orders; +using com::centreon::exceptions::msg_fmt; parser::parser( const shared_io_context& io_context, @@ -54,9 +55,8 @@ void parser::execute(const std::string& cmd) { char* ptr(nullptr); unsigned long long cmd_id(strtoull(cmd.c_str(), &ptr, 10)); if (!cmd_id || *ptr) - throw basic_error() << "invalid execution request received:" - " bad command ID (" - << cmd.c_str() << ")"; + throw msg_fmt("invalid execution request received: bad command ID ({})", + cmd); size_t pos = end + 1; // Find timeout value. end = cmd.find('\0', pos); @@ -64,17 +64,15 @@ void parser::execute(const std::string& cmd) { time_point ts_timeout = system_clock::now() + std::chrono::seconds(timeout); if (*ptr) - throw basic_error() << "invalid execution request received:" - " bad timeout (" - << cmd.c_str() + pos << ")"; + throw msg_fmt("invalid execution request received: bad timeout ({})", + cmd.c_str() + pos); pos = end + 1; // Find start time. end = cmd.find('\0', pos); strtoull(cmd.c_str() + pos, &ptr, 10); if (*ptr) - throw basic_error() << "invalid execution request received:" - " bad start time (" - << cmd.c_str() + pos << ")"; + throw msg_fmt("invalid execution request received: bad start time ({})", + cmd.c_str() + pos); pos = end + 1; // Find command to execute. end = cmd.find('\0', pos); diff --git a/connectors/perl/test/connector.cc b/connectors/perl/test/connector.cc index 1fc317d61f6..a0396074875 100644 --- a/connectors/perl/test/connector.cc +++ b/connectors/perl/test/connector.cc @@ -22,7 +22,7 @@ #include "com/centreon/clib.hh" #include "com/centreon/connector/log.hh" -#include "com/centreon/exceptions/basic.hh" +#include "com/centreon/exceptions/msg_fmt.hh" #include "com/centreon/io/file_stream.hh" #include "com/centreon/misc/command_line.hh" @@ -33,7 +33,8 @@ using system_clock = std::chrono::system_clock; using time_point = system_clock::time_point; using duration = system_clock::duration; -static std::string perl_connector = BUILD_PATH "/connectors/perl/" +static std::string perl_connector = BUILD_PATH + "/connectors/perl/" "centreon_connector_perl --debug --log-file=/data/dev/connector.log"; static constexpr const char cmd1[] = @@ -169,12 +170,12 @@ void process::start() { int out_pipe[2]; if (pipe(in_pipe)) { char const* msg(strerror(errno)); - throw basic_error() << msg; + throw msg_fmt("{}", msg); } else if (pipe(err_pipe)) { char const* msg(strerror(errno)); close(in_pipe[0]); close(in_pipe[1]); - throw basic_error() << msg; + throw msg_fmt("{}", msg); } if (pipe(out_pipe)) { char const* msg(strerror(errno)); @@ -182,7 +183,7 @@ void process::start() { close(in_pipe[1]); close(err_pipe[0]); close(err_pipe[1]); - throw basic_error() << msg; + throw msg_fmt("{}", msg); } _io_context->notify_fork(asio::io_context::fork_prepare); @@ -246,7 +247,7 @@ void process::start() { close(out_pipe[1]); close(err_pipe[0]); close(err_pipe[1]); - throw basic_error() << msg; + throw msg_fmt("{}", msg); } } @@ -273,7 +274,7 @@ void process::write(const std::string& data, const duration& time_out) { std::unique_lock l(_protect); _wait_for_completion.wait_for(l, time_out); if (buff->first) { - throw basic_error() << "fail to write:" << buff->first.message(); + throw msg_fmt("fail to write:{}", buff->first.message()); } } @@ -298,8 +299,7 @@ std::string process::read_std_out(const duration& time_out) { } log::core()->error("fail to read from std_out:{}", std::get<0>(*data).message()); - throw basic_error() << "fail to read from std_out:" - << std::get<0>(*data).message(); + throw msg_fmt("fail to read from std_out:{}", std::get<0>(*data).message()); } return std::string(std::get<2>(*data).data(), std::get<2>(*data).data() + std::get<1>(*data)); @@ -326,8 +326,7 @@ std::string process::read_std_err(const duration& time_out) { } log::core()->error("fail to read from std_err:{}", std::get<0>(*data).message()); - throw basic_error() << "fail to read from std_err:" - << std::get<0>(*data).message(); + throw msg_fmt("fail to read from std_err:{}", std::get<0>(*data).message()); } return std::string(std::get<2>(*data).data(), std::get<2>(*data).data() + std::get<1>(*data)); @@ -375,14 +374,14 @@ class TestConnector : public testing::Test { // Open file. FILE* f(fopen(filename, "w")); if (!f) - throw basic_error() << "could not open file " << filename; + throw msg_fmt("could not open file {}", filename); // Write content. while (size > 0) { size_t wb(fwrite(content, sizeof(*content), size, f)); if (ferror(f)) { fclose(f); - throw basic_error() << "error while writing file " << filename; + throw msg_fmt("error while writing file {}", filename); } size -= wb; } diff --git a/connectors/ssh/src/checks/check.cc b/connectors/ssh/src/checks/check.cc index 54c155e4dfc..3bc152e5b51 100644 --- a/connectors/ssh/src/checks/check.cc +++ b/connectors/ssh/src/checks/check.cc @@ -17,12 +17,13 @@ */ #include "com/centreon/connector/log.hh" -#include "com/centreon/exceptions/basic.hh" +#include "com/centreon/exceptions/msg_fmt.hh" #include "com/centreon/connector/ssh/checks/check.hh" #include "com/centreon/connector/ssh/sessions/session.hh" using namespace com::centreon::connector::ssh::checks; +using com::centreon::exceptions::msg_fmt; namespace com::centreon::connector::ssh::checks { std::ostream& operator<<(std::ostream& os, const check& chk) { @@ -134,7 +135,7 @@ void check::_process() { _close(); } break; default: - throw basic_error() << "channel requested to run at invalid step"; + throw msg_fmt("channel requested to run at invalid step"); } } diff --git a/connectors/ssh/src/main.cc b/connectors/ssh/src/main.cc index cb11efe0b44..ce9f75d031c 100644 --- a/connectors/ssh/src/main.cc +++ b/connectors/ssh/src/main.cc @@ -1,26 +1,26 @@ /** -* Copyright 2011-2013 Centreon -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* For more information : contact@centreon.com -*/ + * Copyright 2011-2013 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ #include "com/centreon/connector/log.hh" #include "com/centreon/connector/ssh/options.hh" #include "com/centreon/connector/ssh/policy.hh" #include "com/centreon/connector/ssh/sessions/session.hh" -#include "com/centreon/exceptions/basic.hh" +#include "com/centreon/exceptions/msg_fmt.hh" using namespace com::centreon; using namespace com::centreon::connector; @@ -46,7 +46,7 @@ int main(int argc, char* argv[]) { std::string test_file_path; try { opts.parse(argc - 1, argv + 1); - } catch (exceptions::basic const& e) { + } catch (exceptions::msg_fmt const& e) { std::cout << e.what() << std::endl << opts.usage() << std::endl; return EXIT_FAILURE; } @@ -77,13 +77,12 @@ int main(int argc, char* argv[]) { // Initialize libssh2. log::core()->debug("initializing libssh2"); if (libssh2_init(0)) - throw basic_error() << "libssh2 initialization failed"; + throw exceptions::msg_fmt("libssh2 initialization failed"); { char const* version(libssh2_version(LIBSSH2_VERSION_NUM)); if (!version) - throw basic_error() - << "libssh2 version is too old (>= " << LIBSSH2_VERSION - << " required)"; + throw exceptions::msg_fmt( + "libssh2 version is too old (>= " LIBSSH2_VERSION " required)"); log::core()->info("libssh2 version {} successfully loaded", version); } diff --git a/connectors/ssh/src/orders/options.cc b/connectors/ssh/src/orders/options.cc index 4fbec37c2dc..c2643329e1b 100644 --- a/connectors/ssh/src/orders/options.cc +++ b/connectors/ssh/src/orders/options.cc @@ -1,20 +1,20 @@ /** -* Copyright 2011-2013 Centreon -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* For more information : contact@centreon.com -*/ + * Copyright 2011-2013 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ #ifdef _WIN32 #include @@ -28,10 +28,11 @@ #include #include "absl/strings/numbers.h" #include "com/centreon/connector/ssh/orders/options.hh" -#include "com/centreon/exceptions/basic.hh" +#include "com/centreon/exceptions/msg_fmt.hh" #include "com/centreon/misc/command_line.hh" using namespace com::centreon::connector::orders; +using com::centreon::exceptions::msg_fmt; static char const* optstr = "1246a:C:E:fhH:i:l:n:o:O:p:qs:S:t:vV"; static struct option optlong[] = { @@ -221,12 +222,13 @@ void options::parse(std::string const& cmdline) { { unsigned int temp; if (!absl::SimpleAtoi(optarg, &temp)) { - throw basic_error() << "the argument '" << optarg - << "' must be an unsigned short integer"; + throw msg_fmt("the argument '{}' must be an unsigned short integer", + optarg); } if (temp > 65535) { - throw basic_error() << "the argument '" << optarg - << "' must be an integer between 0 and 65535"; + throw msg_fmt( + "the argument '{}' must be an integer between 0 and 65535", + optarg); } _port = temp; } break; @@ -240,7 +242,7 @@ void options::parse(std::string const& cmdline) { break; case '1': // Enable SSH v1. - throw basic_error() << "'" << c << "' option is not supported"; + throw msg_fmt("'{}' option is not supported", c); break; case '2': // Enable SSH v2. @@ -251,13 +253,12 @@ void options::parse(std::string const& cmdline) { if (!optarg) _skip_stderr = 0; else if (!absl::SimpleAtoi(optarg, &_skip_stderr)) { - throw basic_error() - << "the argument '" << optarg << "' must be an integer"; + throw msg_fmt("the argument '{}' must be an integer", optarg); } break; case 'f': // Fork ssh. - throw basic_error() << "'" << c << "' option is not supported"; + throw msg_fmt("'{}' option is not supported", c); break; case 'i': // Set Identity file. @@ -265,34 +266,24 @@ void options::parse(std::string const& cmdline) { break; case 'n': // Host name for monitoring engine. - throw basic_error() << "'" << c << "' option is not supported"; - break; - case 'o': // Set ssh-option. - throw basic_error() << "'" << c << "' option is not supported"; - break; - case 'O': // Set output file. - throw basic_error() << "'" << c << "' option is not supported"; - break; - case 's': // Services. - throw basic_error() << "'" << c << "' option is not supported"; + throw msg_fmt("'{}' option is not supported", c); break; case 'S': // Skip stdout. if (!optarg) _skip_stdout = 0; else if (!absl::SimpleAtoi(optarg, &_skip_stdout)) { - throw basic_error() - << "the argument '" << optarg << "' must be an integer"; + throw msg_fmt("the argument '{}' must be an integer", optarg); } break; case 't': // Set timeout. if (!absl::SimpleAtoi(optarg, &_timeout)) { - throw basic_error() - << "the argument '" << optarg << "' must be an unsigned integer"; + throw msg_fmt("the argument '{}' must be an unsigned integer", + optarg); } break; @@ -304,10 +295,10 @@ void options::parse(std::string const& cmdline) { break; case '?': // Missing argument. - throw basic_error() << "option '" << c << "' requires an argument"; + throw msg_fmt("option '{}' requires an argument", c); default: // Unknown argument. - throw basic_error() << "unrecognized option '" << c << "'"; + throw msg_fmt("unrecognized option '{}'", c); } } if (_user.empty()) @@ -342,7 +333,7 @@ std::string options::_get_user_name() { passwd* pwd(getpwuid(getuid())); if (!pwd || !pwd->pw_name) { char const* msg(strerror(errno)); - throw basic_error() << "cannot get current user name: " << msg; + throw msg_fmt("cannot get current user name: {}", msg); } return pwd->pw_name; } diff --git a/connectors/ssh/src/orders/parser.cc b/connectors/ssh/src/orders/parser.cc index fd957aceb52..607ccea2d1f 100644 --- a/connectors/ssh/src/orders/parser.cc +++ b/connectors/ssh/src/orders/parser.cc @@ -1,27 +1,28 @@ /** -* Copyright 2011-2014, 2022 Centreon -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* For more information : contact@centreon.com -*/ + * Copyright 2011-2014, 2022 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ #include "com/centreon/connector/ssh/orders/parser.hh" #include "com/centreon/connector/log.hh" #include "com/centreon/connector/ssh/policy.hh" -#include "com/centreon/exceptions/basic.hh" +#include "com/centreon/exceptions/msg_fmt.hh" using namespace com::centreon::connector::ssh::orders; +using com::centreon::exceptions::msg_fmt; parser::parser( const shared_io_context& io_context, @@ -59,51 +60,47 @@ void parser::execute(const std::string& cmd) { char* ptr(nullptr); unsigned long long cmd_id(strtoull(cmd.c_str(), &ptr, 10)); if (!cmd_id || *ptr) - throw basic_error() << "invalid execution request received:" - " bad command ID (" - << cmd << ")"; + throw msg_fmt("invalid execution request received: bad command ID ({})", + cmd); size_t pos = end + 1; // Find timeout value. end = cmd.find('\0', pos); time_t timeout(static_cast(strtoull(cmd.c_str() + pos, &ptr, 10))); if (*ptr) - throw basic_error() << "invalid execution request received:" - " bad timeout (" - << cmd.c_str() + pos << ")"; + throw msg_fmt("invalid execution request received: bad timeout ({})", + cmd.c_str() + pos); time_point ts_timeout = system_clock::now() + std::chrono::seconds(timeout); pos = end + 1; // Find start time. end = cmd.find('\0', pos); time_t start_time(static_cast(strtoull(cmd.c_str() + pos, &ptr, 10))); if (*ptr || !start_time) - throw basic_error() << "invalid execution request received:" - " bad start time (" - << cmd.c_str() + pos << ")"; + throw msg_fmt("invalid execution request received: bad start time ({})", + cmd.c_str() + pos); pos = end + 1; // Find command to execute. end = cmd.find('\0', pos); std::string cmdline(cmd.substr(pos, end - pos)); if (cmdline.empty()) - throw basic_error() << "invalid execution request received:" - " bad command line (" - << cmd.c_str() + pos << ")"; + throw msg_fmt("invalid execution request received: bad command line ({})", + cmd.c_str() + pos); com::centreon::connector::orders::options::pointer opt( std::make_shared()); try { opt->parse(cmdline); if (opt->get_commands().empty()) - throw basic_error() << "invalid execution request " - "received: bad command line (" - << cmd.c_str() + pos << ")"; + throw msg_fmt("invalid execution request received: bad command line ({})", + cmd.c_str() + pos); if (opt->get_timeout() && opt->get_timeout() < static_cast(timeout)) ts_timeout = system_clock::now() + std::chrono::seconds(opt->get_timeout()); else if (opt->get_timeout() > static_cast(timeout)) - throw basic_error() << "invalid execution request " - "received: timeout > to monitoring engine timeout"; + throw msg_fmt( + "invalid execution request received: timeout > to monitoring engine " + "timeout"); } catch (std::exception const& e) { log::core()->error("fail to parse cmd line {} {}", cmdline, e.what()); _owner->on_error(cmd_id, e.what()); diff --git a/connectors/ssh/src/sessions/session.cc b/connectors/ssh/src/sessions/session.cc index fad74b3f590..a7dd7e5d0e6 100644 --- a/connectors/ssh/src/sessions/session.cc +++ b/connectors/ssh/src/sessions/session.cc @@ -19,13 +19,14 @@ #include #include "com/centreon/connector/log.hh" -#include "com/centreon/exceptions/basic.hh" +#include "com/centreon/exceptions/msg_fmt.hh" #include "com/centreon/connector/ssh/sessions/session.hh" using namespace com::centreon; using namespace com::centreon::connector; using namespace com::centreon::connector::ssh::sessions; +using com::centreon::exceptions::msg_fmt; namespace com::centreon::connector::ssh::sessions { std::ostream& operator<<(std::ostream& os, const session& sess) { @@ -66,7 +67,7 @@ session::session(credentials const& creds, const shared_io_context& io_context) // Create session instance. _session = libssh2_session_init_ex(nullptr, nullptr, nullptr, this); if (!_session) - throw basic_error() << "SSH session creation failed (out of memory ?)"; + throw msg_fmt("SSH session creation failed (out of memory ?)"); libssh2_session_callback_set(_session, LIBSSH2_CALLBACK_RECV, (void*)g_socket_recv); libssh2_session_callback_set(_session, LIBSSH2_CALLBACK_SEND, @@ -623,7 +624,7 @@ void session::handshake_handler(int retval, if (!known_hosts) { char* msg; libssh2_session_last_error(_session, &msg, nullptr, 0); - throw basic_error() << "could not create known hosts list: " << msg; + throw msg_fmt("could not create known hosts list: {}", msg); } // Get home directory. @@ -639,8 +640,8 @@ void session::handshake_handler(int retval, int rh(libssh2_knownhost_readfile(known_hosts, known_hosts_file.c_str(), LIBSSH2_KNOWNHOST_FILE_OPENSSH)); if (rh < 0) - throw basic_error() << "parsing of known_hosts file " << known_hosts_file - << " failed: error " << -rh; + throw msg_fmt("parsing of known_hosts file {} failed: error {}", + known_hosts_file, -rh); else log_info(logging::medium) << rh << " hosts found in known_hosts file " << known_hosts_file; @@ -658,7 +659,7 @@ void session::handshake_handler(int retval, char* msg; libssh2_session_last_error(_session, &msg, nullptr, 0); libssh2_knownhost_free(known_hosts); - throw basic_error() << "failed to get remote host fingerprint: " << msg; + throw msg_fmt("failed to get remote host fingerprint: {}", msg); } // Check fingerprint. @@ -672,17 +673,20 @@ void session::handshake_handler(int retval, // Check fingerprint. if (check != LIBSSH2_KNOWNHOST_CHECK_MATCH) { - exceptions::basic e(basic_error()); - e << "host '" << _creds.get_host() - << "' is not known or could not be validated: "; if (LIBSSH2_KNOWNHOST_CHECK_NOTFOUND == check) - e << "host was not found in known_hosts file " << known_hosts_file; + throw msg_fmt( + "host '{}' is not known or could not be validated: host was not " + "found in known_hosts file {}", + _creds.get_host(), known_hosts_file); else if (LIBSSH2_KNOWNHOST_CHECK_MISMATCH == check) - e << "host fingerprint mismatch with known_hosts file " - << known_hosts_file; + throw msg_fmt( + "host '{}' is not known or could not be validated: host " + "fingerprint mismatch with known_hosts file {}", + _creds.get_host(), known_hosts_file); else - e << "unknown error"; - throw e; + throw msg_fmt( + "host '{}' is not known or could not be validated: unknown error", + _creds.get_host()); } log_info(logging::medium) << "fingerprint on session " << _creds.get_user() << "@" << _creds.get_host() << ":" @@ -693,4 +697,4 @@ void session::handshake_handler(int retval, _step_string = "password authentication"; _passwd(callback, timeout); } -} +} \ No newline at end of file diff --git a/connectors/ssh/test/connector/command_execute.cc b/connectors/ssh/test/connector/command_execute.cc index 1958a8c0218..5ac439b1e37 100644 --- a/connectors/ssh/test/connector/command_execute.cc +++ b/connectors/ssh/test/connector/command_execute.cc @@ -1,30 +1,31 @@ /** -* Copyright 2012-2013 Centreon -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* For more information : contact@centreon.com -*/ + * Copyright 2012-2013 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ #include #include #include #include -#include "com/centreon/exceptions/basic.hh" +#include "com/centreon/exceptions/msg_fmt.hh" #include "com/centreon/process.hh" #include "test/connector/binary.hh" using namespace com::centreon; +using com::centreon::exceptions::msg_fmt; #define CMD1 \ "2\0" \ @@ -98,11 +99,11 @@ int main() { try { if (retval) - throw basic_error() << "invalid return code: " << retval; + throw msg_fmt("invalid return code: {}", retval); if (output.size() != sizeof(RESULT) - 1 || memcmp(output.c_str(), RESULT, sizeof(RESULT) - 1)) - throw basic_error() << "invalid output: size=" << output.size() - << ", output=" << replace_null(output); + throw msg_fmt("invalid output: size={}, output={}", output.size(), + replace_null(output)); } catch (std::exception const& e) { retval = 1; std::cerr << "error: " << e.what() << std::endl; diff --git a/connectors/ssh/test/connector/command_execute_log_file.cc b/connectors/ssh/test/connector/command_execute_log_file.cc index 641d637531e..4de88bd5086 100644 --- a/connectors/ssh/test/connector/command_execute_log_file.cc +++ b/connectors/ssh/test/connector/command_execute_log_file.cc @@ -1,33 +1,34 @@ /** -* Copyright 2012-2013 Centreon -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* For more information : contact@centreon.com -*/ + * Copyright 2012-2013 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ #include #include #include #include #include -#include "com/centreon/exceptions/basic.hh" +#include "com/centreon/exceptions/msg_fmt.hh" #include "com/centreon/process.hh" #include "test/connector/binary.hh" #define LOG_FILE "/tmp/toto" using namespace com::centreon; +using com::centreon::exceptions::msg_fmt; #define CMD1 \ "2\0" \ @@ -110,25 +111,24 @@ int main() { try { if (retval) - throw(basic_error() << "invalid return code: " << retval); + throw msg_fmt("invalid return code: {}", retval); if (output.size() != (sizeof(RESULT) - 1) || memcmp(output.c_str(), RESULT, sizeof(RESULT) - 1)) - throw(basic_error() << "invalid output: size=" << output.size() - << ", output=" << replace_null(output)); + throw msg_fmt("invalid output: size={}, output={}", output.size(), + replace_null(output)); std::string line; std::ifstream file(LOG_FILE); if (file.is_open()) { getline(file, line); - if (line.find( - "[info] Centreon SSH Connector " CENTREON_CONNECTOR_VERSION - " starting") == std::string::npos) - throw(basic_error() - << "bad content: the first line does not start with 'Centreon " - "SSH Connector " CENTREON_CONNECTOR_VERSION " starting'"); + if (line.find("[info] Centreon SSH Connector " CENTREON_CONNECTOR_VERSION + " starting") == std::string::npos) + throw msg_fmt( + "bad content: the first line does not start with 'Centreon " + "SSH Connector " CENTREON_CONNECTOR_VERSION " starting'"); file.close(); } else { - throw(basic_error() << "the file " LOG_FILE " has not been created."); + throw msg_fmt("the file " LOG_FILE " has not been created."); } } catch (std::exception const& e) { retval = 1; diff --git a/connectors/ssh/test/connector/command_version.cc b/connectors/ssh/test/connector/command_version.cc index d5773c78341..4f3dd574e4e 100644 --- a/connectors/ssh/test/connector/command_version.cc +++ b/connectors/ssh/test/connector/command_version.cc @@ -1,28 +1,29 @@ /** -* Copyright 2012-2013 Centreon -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* For more information : contact@centreon.com -*/ + * Copyright 2012-2013 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ #include #include -#include "com/centreon/exceptions/basic.hh" +#include "com/centreon/exceptions/msg_fmt.hh" #include "com/centreon/process.hh" #include "test/connector/binary.hh" using namespace com::centreon; +using com::centreon::exceptions::msg_fmt; #define CMD "0\0\0\0\0" #define RESULT "1\0001\0000\0\0\0\0" @@ -69,11 +70,11 @@ int main() { try { if (retval) - throw basic_error() << "invalid return code: " << retval; + throw msg_fmt("invalid return code: {}", retval); if (output.size() != sizeof(RESULT) - 1 || memcmp(output.c_str(), RESULT, sizeof(RESULT) - 1)) - throw basic_error() << "invalid output: size=" << output.size() - << ", output=" << output; + throw msg_fmt("invalid output: size={}, output={}", output.size(), + output); } catch (std::exception const& e) { retval = 1; std::cerr << "error: " << e.what() << std::endl; diff --git a/connectors/ssh/test/connector/non_existent_host.cc b/connectors/ssh/test/connector/non_existent_host.cc index 4ee4f0340ef..1cd00fc5503 100644 --- a/connectors/ssh/test/connector/non_existent_host.cc +++ b/connectors/ssh/test/connector/non_existent_host.cc @@ -1,30 +1,31 @@ /** -* Copyright 2012-2013 Centreon -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* For more information : contact@centreon.com -*/ + * Copyright 2012-2013 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ #include #include #include #include -#include "com/centreon/exceptions/basic.hh" +#include "com/centreon/exceptions/msg_fmt.hh" #include "com/centreon/process.hh" #include "test/connector/binary.hh" using namespace com::centreon; +using com::centreon::exceptions::msg_fmt; #define CMD1 \ "2\0" \ @@ -87,11 +88,11 @@ int main() { try { if (retval) - throw(basic_error() << "invalid return code: " << retval); + throw msg_fmt("invalid return code: {}", retval); if (output.size() != (sizeof(RESULT) - 1) || memcmp(output.c_str(), RESULT, sizeof(RESULT) - 1)) - throw(basic_error() << "invalid output: size=" << output.size() - << ", output=" << output); + throw msg_fmt("invalid output: size={}, output={}", output.size(), + output); } catch (std::exception const& e) { retval = 1; std::cerr << "error: " << e.what() << std::endl; diff --git a/connectors/ssh/test/connector/single_check_timeout.cc b/connectors/ssh/test/connector/single_check_timeout.cc index a83c30b00f3..f6dc6bc02e6 100644 --- a/connectors/ssh/test/connector/single_check_timeout.cc +++ b/connectors/ssh/test/connector/single_check_timeout.cc @@ -1,20 +1,20 @@ /** -* Copyright 2012-2013 Centreon -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -* -* For more information : contact@centreon.com -*/ + * Copyright 2012-2013 Centreon + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * For more information : contact@centreon.com + */ #include #include @@ -23,11 +23,12 @@ #include #include #include -#include "com/centreon/exceptions/basic.hh" +#include "com/centreon/exceptions/msg_fmt.hh" #include "com/centreon/process.hh" #include "test/connector/binary.hh" using namespace com::centreon; +using com::centreon::exceptions::msg_fmt; #define CMD1 \ "2\0" \ @@ -92,11 +93,11 @@ int main() { try { if (retval) - throw(basic_error() << "invalid return code: " << retval); + throw msg_fmt("invalid return code: {}", retval); if (output.size() != (sizeof(RESULT) - 1) || memcmp(output.c_str(), RESULT, sizeof(RESULT) - 1)) - throw(basic_error() << "invalid output: size=" << output.size() - << ", output=" << output); + throw msg_fmt("invalid output: size={}, output={}", output.size(), + output); } catch (std::exception const& e) { retval = 1; std::cerr << "error: " << e.what() << std::endl; diff --git a/connectors/ssh/test/reporter.cc b/connectors/ssh/test/reporter.cc index 54d97480a17..372be101e87 100644 --- a/connectors/ssh/test/reporter.cc +++ b/connectors/ssh/test/reporter.cc @@ -21,8 +21,6 @@ #include -#include "com/centreon/exceptions/basic.hh" - using namespace com::centreon; using namespace com::centreon::connector; diff --git a/engine/enginerpc/engine.proto b/engine/enginerpc/engine.proto index f11b867dda0..eeb9d0bda19 100644 --- a/engine/enginerpc/engine.proto +++ b/engine/enginerpc/engine.proto @@ -356,6 +356,122 @@ message EngineHost { UNREACHABLE = 2; } State current_state = 6; + string display_name = 7; + repeated string parent_hosts = 8; + repeated string child_hosts = 9; + repeated string services = 10; + string check_command = 11; + State initial_state = 12; + uint32 check_interval = 13; + double retry_interval = 14; + int32 max_attempts = 15; + string event_handler = 16; + repeated string contactgroups = 17; + repeated string contacts = 18; + uint32 notification_interval = 19; + uint32 first_notification_delay = 20; + uint32 recovery_notification_delay = 21; + bool notify_up = 22; + bool notify_down = 23; + bool notify_unreachable = 24; + bool notify_on_flappingstart = 25; + bool notify_on_flappingstop = 26; + bool notify_on_flappingdisabled = 27; + bool notify_downtime = 28; + string notification_period = 29; + bool flap_detection_enabled = 30; + double low_flap_threshold = 31; + double high_flap_threshold = 32; + bool flap_detection_on_up = 33; + bool flap_detection_on_down = 34; + bool flap_detection_on_unreachable = 35; + bool stalk_on_up = 36; + bool stalk_on_down = 37; + bool stalk_on_unreachable = 38; + bool check_freshness = 39; + int32 freshness_threshold = 40; + bool process_performance_data = 41; + bool checks_enabled = 42; + bool accept_passive_checks = 43; + bool event_handler_enabled = 44; + int32 retain_status_information = 45; + bool retain_nonstatus_information = 46; + bool obsess_over_host = 47; + string notes = 48; + string notes_url = 49; + string action_url = 50; + string icon_image = 51; + string icon_image_alt = 52; + string vrml_image = 53; + string statusmap_image = 54; + bool have_2d_coords = 55; + double x_2d = 56; + double y_2d = 57; + bool have_3d_coords = 58; + double x_3d = 59; + double y_3d = 60; + double z_3d = 61; + int32 should_be_drawn = 62; + enum AckType { + NONE = 0; + NORMAL = 1; + STICKY = 2; + } + AckType acknowledgement = 63; + enum CheckType { + CHECK_ACTIVE = 0; + CHECK_PASSIVE = 1; + } + CheckType check_type = 64; + State last_state = 65; + State last_hard_state = 66; + string plugin_output = 67; + string long_plugin_output = 68; + string perf_data = 69; + State state_type = 70; + int32 current_attempt = 71; + uint64 current_event_id = 72; + uint64 last_event_id = 73; + uint64 current_problem_id = 74; + uint64 last_problem_id = 75; + double latency = 76; + double execution_time = 77; + bool is_executing = 78; + int32 check_options = 79; + bool notifications_enabled = 80; + string last_notification = 81; + string next_notification = 82; + string next_check = 83; + bool should_be_scheduled = 84; + string last_check = 85; + string last_state_change = 86; + string last_hard_state_change = 87; + string last_time_up = 88; + string last_time_down = 89; + string last_time_unreachable = 90; + bool has_been_checked = 91; + bool is_being_freshened = 92; + bool notified_on_down = 93; + bool notified_on_unreachable = 94; + bool no_more_notifications = 95; + uint64 current_notification_id = 96; + int32 scheduled_downtime_depth = 97; + int32 pending_flex_downtime = 98; + string state_history = 99; + uint32 state_history_index = 100; + string last_state_history_update = 101; + bool is_flapping = 102; + uint64 flapping_comment_id = 103; + double percent_state_change = 104; + int32 total_services = 105; + uint64 total_service_check_interval = 106; + uint32 modified_attributes = 107; + int32 circular_path_checked = 108; + bool contains_circular_path = 109; + string timezone = 110; + uint64 icon_id = 111; + string group_name = 112; + repeated string custom_variables = 113; } message ContactIdentifier { diff --git a/engine/enginerpc/engine_impl.cc b/engine/enginerpc/engine_impl.cc index a96819137d6..07ce45d2fc9 100644 --- a/engine/enginerpc/engine_impl.cc +++ b/engine/enginerpc/engine_impl.cc @@ -22,51 +22,33 @@ #include -namespace asio = boost::asio; - #include #include #include #include -#include -#include #include "com/centreon/common/process_stat.hh" #include "com/centreon/common/time.hh" -#include "com/centreon/engine/host.hh" -#include "com/centreon/engine/anomalydetection.hh" #include "com/centreon/engine/broker.hh" #include "com/centreon/engine/command_manager.hh" #include "com/centreon/engine/commands/commands.hh" #include "com/centreon/engine/commands/processing.hh" -#include "com/centreon/engine/comment.hh" -#include "com/centreon/engine/common.hh" -#include "com/centreon/engine/contact.hh" -#include "com/centreon/engine/contactgroup.hh" -#include "com/centreon/engine/downtimes/downtime.hh" #include "com/centreon/engine/downtimes/downtime_finder.hh" #include "com/centreon/engine/downtimes/downtime_manager.hh" #include "com/centreon/engine/downtimes/service_downtime.hh" -#include "com/centreon/engine/engine_impl.hh" #include "com/centreon/engine/events/loop.hh" #include "com/centreon/engine/globals.hh" -#include "com/centreon/engine/hostdependency.hh" -#include "com/centreon/engine/hostgroup.hh" -#include "com/centreon/engine/logging/logger.hh" -#include "com/centreon/engine/service.hh" -#include "com/centreon/engine/servicedependency.hh" -#include "com/centreon/engine/servicegroup.hh" -#include "com/centreon/engine/statistics.hh" +#include "com/centreon/engine/severity.hh" #include "com/centreon/engine/statusdata.hh" +#include "com/centreon/engine/string.hh" #include "com/centreon/engine/version.hh" -#include "common/log_v2/log_v2.hh" using namespace com::centreon::engine; -using namespace com::centreon::engine::logging; using namespace com::centreon::engine::downtimes; +using namespace com::centreon::engine::string; using com::centreon::common::log_v2::log_v2; @@ -234,24 +216,191 @@ grpc::Status engine_impl::GetHost(grpc::ServerContext* context [[maybe_unused]], [[maybe_unused]], EngineHost* response) { std::string err; - auto fn = std::packaged_task( - [&err, request, host = response]() -> int32_t { - std::shared_ptr selectedhost; - std::tie(selectedhost, err) = get_host(*request); - if (!err.empty()) { - return 1; - } - host->set_name(selectedhost->name()); - host->set_alias(selectedhost->get_alias()); - host->set_address(selectedhost->get_address()); - host->set_check_period(selectedhost->check_period()); - host->set_current_state( - static_cast(selectedhost->get_current_state())); - host->set_id(selectedhost->host_id()); - return 0; - }); + auto fn = std::packaged_task([&err, request, + host = response]() -> int32_t { + std::shared_ptr selectedhost; + std::tie(selectedhost, err) = get_host(*request); + + if (!err.empty()) { + return 1; + } + + host->set_name(selectedhost->name()); + host->set_alias(selectedhost->get_alias()); + host->set_address(selectedhost->get_address()); + host->set_check_period(selectedhost->check_period()); + host->set_id(selectedhost->host_id()); + host->set_current_state( + static_cast(selectedhost->get_current_state())); + host->set_display_name(selectedhost->get_display_name()); + + if (!selectedhost->parent_hosts.empty()) + for (const auto& [key, _] : selectedhost->parent_hosts) + host->add_parent_hosts(key); + + if (!selectedhost->child_hosts.empty()) + for (const auto& [key, _] : selectedhost->child_hosts) + host->add_child_hosts(key); + + if (!selectedhost->services.empty()) + for (const auto& [key, _] : selectedhost->services) + host->add_services(fmt::format("{},{}", key.first, key.second)); + + host->set_check_command(selectedhost->check_command()); + host->set_initial_state( + static_cast(selectedhost->get_initial_state())); + host->set_check_interval(selectedhost->check_interval()); + host->set_retry_interval(selectedhost->retry_interval()); + host->set_max_attempts(selectedhost->max_check_attempts()); + host->set_event_handler(selectedhost->event_handler()); + + if (!selectedhost->get_contactgroups().empty()) + for (const auto& [key, _] : selectedhost->get_contactgroups()) + host->add_contactgroups(key); + + if (!selectedhost->contacts().empty()) + for (const auto& [key, _] : selectedhost->contacts()) + host->add_contacts(key); + + host->set_notification_interval(selectedhost->get_notification_interval()); + host->set_first_notification_delay( + selectedhost->get_first_notification_delay()); + host->set_recovery_notification_delay( + selectedhost->get_recovery_notification_delay()); + host->set_notify_up(selectedhost->get_notify_on(notifier::up)); + host->set_notify_down(selectedhost->get_notify_on(notifier::down)); + host->set_notify_unreachable( + selectedhost->get_notify_on(notifier::unreachable)); + host->set_notify_on_flappingstart( + selectedhost->get_notify_on(notifier::flappingstart)); + host->set_notify_on_flappingstop( + selectedhost->get_notify_on(notifier::flappingstop)); + host->set_notify_on_flappingdisabled( + selectedhost->get_notify_on(notifier::flappingdisabled)); + host->set_notify_downtime(selectedhost->get_notify_on(notifier::downtime)); + host->set_notification_period(selectedhost->notification_period()); + host->set_flap_detection_enabled(selectedhost->flap_detection_enabled()); + host->set_low_flap_threshold(selectedhost->get_low_flap_threshold()); + host->set_high_flap_threshold(selectedhost->get_high_flap_threshold()); + host->set_flap_detection_on_up( + selectedhost->get_flap_detection_on(notifier::up)); + host->set_flap_detection_on_down( + selectedhost->get_flap_detection_on(notifier::down)); + host->set_flap_detection_on_unreachable( + selectedhost->get_flap_detection_on(notifier::unreachable)); + host->set_stalk_on_up(selectedhost->get_stalk_on(notifier::up)); + host->set_stalk_on_down(selectedhost->get_stalk_on(notifier::down)); + host->set_stalk_on_unreachable( + selectedhost->get_stalk_on(notifier::unreachable)); + host->set_check_freshness(selectedhost->check_freshness_enabled()); + host->set_freshness_threshold(selectedhost->get_freshness_threshold()); + host->set_process_performance_data( + selectedhost->get_process_performance_data()); + host->set_checks_enabled(selectedhost->active_checks_enabled()); + host->set_accept_passive_checks(selectedhost->passive_checks_enabled()); + host->set_event_handler_enabled(selectedhost->event_handler_enabled()); + host->set_retain_status_information( + selectedhost->get_retain_status_information()); + host->set_retain_nonstatus_information( + selectedhost->get_retain_nonstatus_information()); + host->set_obsess_over_host(selectedhost->obsess_over()); + host->set_notes(selectedhost->get_notes()); + host->set_notes_url(selectedhost->get_notes_url()); + host->set_action_url(selectedhost->get_action_url()); + host->set_icon_image(selectedhost->get_icon_image()); + host->set_icon_image_alt(selectedhost->get_icon_image_alt()); + host->set_vrml_image(selectedhost->get_vrml_image()); + host->set_statusmap_image(selectedhost->get_statusmap_image()); + host->set_have_2d_coords(selectedhost->get_have_2d_coords()); + host->set_x_2d(selectedhost->get_x_2d()); + host->set_y_2d(selectedhost->get_y_2d()); + host->set_have_3d_coords(selectedhost->get_have_3d_coords()); + host->set_x_3d(selectedhost->get_x_3d()); + host->set_y_3d(selectedhost->get_y_3d()); + host->set_z_3d(selectedhost->get_z_3d()); + host->set_should_be_drawn(selectedhost->get_should_be_drawn()); + host->set_acknowledgement( + static_cast(selectedhost->get_acknowledgement())); + host->set_check_type( + static_cast(selectedhost->get_check_type())); + host->set_last_state( + static_cast(selectedhost->get_last_state())); + host->set_last_hard_state( + static_cast(selectedhost->get_last_hard_state())); + host->set_plugin_output(selectedhost->get_plugin_output()); + host->set_long_plugin_output(selectedhost->get_long_plugin_output()); + host->set_perf_data(selectedhost->get_perf_data()); + host->set_state_type( + static_cast(selectedhost->get_state_type())); + host->set_current_attempt(selectedhost->get_current_attempt()); + host->set_current_event_id(selectedhost->get_current_event_id()); + host->set_last_event_id(selectedhost->get_last_event_id()); + host->set_current_problem_id(selectedhost->get_current_problem_id()); + host->set_last_problem_id(selectedhost->get_last_problem_id()); + host->set_latency(selectedhost->get_latency()); + host->set_execution_time(selectedhost->get_execution_time()); + host->set_is_executing(selectedhost->get_is_executing()); + host->set_check_options(selectedhost->get_check_options()); + host->set_notifications_enabled(selectedhost->get_notifications_enabled()); + host->set_last_notification( + string::ctime(selectedhost->get_last_notification())); + host->set_next_notification( + string::ctime(selectedhost->get_next_notification())); + host->set_next_check(string::ctime(selectedhost->get_next_check())); + host->set_should_be_scheduled(selectedhost->get_should_be_scheduled()); + host->set_last_check(string::ctime(selectedhost->get_last_check())); + host->set_last_state_change( + string::ctime(selectedhost->get_last_state_change())); + host->set_last_hard_state_change( + string::ctime(selectedhost->get_last_hard_state_change())); + host->set_last_time_up(string::ctime(selectedhost->get_last_time_up())); + host->set_last_time_down(string::ctime(selectedhost->get_last_time_down())); + host->set_last_time_unreachable( + string::ctime(selectedhost->get_last_time_unreachable())); + host->set_has_been_checked(selectedhost->has_been_checked()); + host->set_is_being_freshened(selectedhost->get_is_being_freshened()); + host->set_notified_on_down(selectedhost->get_notified_on(notifier::down)); + host->set_notified_on_unreachable( + selectedhost->get_notified_on(notifier::unreachable)); + host->set_no_more_notifications(selectedhost->get_no_more_notifications()); + host->set_current_notification_id( + selectedhost->get_current_notification_id()); + host->set_scheduled_downtime_depth( + selectedhost->get_scheduled_downtime_depth()); + host->set_pending_flex_downtime(selectedhost->get_pending_flex_downtime()); + + host->set_state_history(fmt::format( + "[{}]", fmt::join(selectedhost->get_state_history(), ", "))); + + host->set_state_history_index(selectedhost->get_state_history_index()); + host->set_last_state_history_update( + string::ctime(selectedhost->get_last_state_history_update())); + host->set_is_flapping(selectedhost->get_is_flapping()); + host->set_flapping_comment_id(selectedhost->get_flapping_comment_id()); + host->set_percent_state_change(selectedhost->get_percent_state_change()); + host->set_total_services(selectedhost->get_total_services()); + host->set_total_service_check_interval( + selectedhost->get_total_service_check_interval()); + host->set_modified_attributes(selectedhost->get_modified_attributes()); + host->set_circular_path_checked(selectedhost->get_circular_path_checked()); + host->set_contains_circular_path( + selectedhost->get_contains_circular_path()); + host->set_timezone(selectedhost->get_timezone()); + host->set_icon_id(selectedhost->get_icon_id()); + + // locals + hostgroup* hg{selectedhost->get_parent_groups().front()}; + host->set_group_name(hg ? hg->get_group_name() : ""); + + for (const auto& cv : selectedhost->custom_variables) + host->add_custom_variables(fmt::format( + "key : {}, value :{}, is_sent :{}, has_been_modified: {} ", cv.first, + cv.second.value(), cv.second.is_sent(), + cv.second.has_been_modified())); + return 0; + }); std::future result = fn.get_future(); command_manager::instance().enqueue(std::move(fn)); int32_t res = result.get(); @@ -775,7 +924,7 @@ grpc::Status engine_impl::RemoveHostAcknowledgement( /* set the acknowledgement flag */ temp_host->set_acknowledgement(AckType::NONE); /* update the status log with the host info */ - temp_host->update_status(); + temp_host->update_status(host::STATUS_ACKNOWLEDGEMENT); /* remove any non-persistant comments associated with the ack */ comment::delete_host_acknowledgement_comments(temp_host.get()); return 0; @@ -815,7 +964,7 @@ grpc::Status engine_impl::RemoveServiceAcknowledgement( /* set the acknowledgement flag */ temp_service->set_acknowledgement(AckType::NONE); /* update the status log with the service info */ - temp_service->update_status(); + temp_service->update_status(service::STATUS_ACKNOWLEDGEMENT); /* remove any non-persistant comments associated with the ack */ comment::delete_service_acknowledgement_comments(temp_service.get()); return 0; @@ -871,7 +1020,7 @@ grpc::Status engine_impl::AcknowledgementHostProblem( request->ack_data(), notifier::notification_option_none); /* update the status log with the host info */ - temp_host->update_status(); + temp_host->update_status(host::STATUS_ACKNOWLEDGEMENT); /* add a comment for the acknowledgement */ auto com = std::make_shared( comment::host, comment::acknowledgment, temp_host->host_id(), 0, @@ -934,7 +1083,7 @@ grpc::Status engine_impl::AcknowledgementServiceProblem( request->ack_author(), request->ack_data(), notifier::notification_option_none); /* update the status log with the service info */ - temp_service->update_status(); + temp_service->update_status(service::STATUS_ACKNOWLEDGEMENT); /* add a comment for the acknowledgement */ auto com = std::make_shared( @@ -1748,7 +1897,7 @@ grpc::Status engine_impl::DeleteServiceDowntimeFull( const DowntimeCriterias* request, CommandSuccess* response [[maybe_unused]]) { std::string err; - auto fn = std::packaged_task([&err, request]() -> int32_t { + auto fn = std::packaged_task([request]() -> int32_t { std::list dtlist; /* iterate through all current downtime(s) */ for (auto it = downtimes::downtime_manager::instance() @@ -1759,7 +1908,8 @@ grpc::Status engine_impl::DeleteServiceDowntimeFull( .end(); it != end; ++it) { service_downtime* dt = static_cast(it->second.get()); - /* we are checking if request criteria match with the downtime criteria */ + /* we are checking if request criteria match with the downtime criteria + */ auto p = engine::get_host_and_service_names(dt->host_id(), dt->service_id()); if (!request->host_name().empty() && p.first != request->host_name()) @@ -2332,8 +2482,7 @@ grpc::Status engine_impl::ChangeHostObjectIntVar(grpc::ServerContext* context /* modify the check interval */ temp_host->set_check_interval(request->dval()); attr = MODATTR_NORMAL_CHECK_INTERVAL; - temp_host->set_modified_attributes( - temp_host->get_modified_attributes() | attr); + temp_host->add_modified_attributes(attr); /* schedule a host check if previous interval was 0 (checks were not * regularly scheduled) */ @@ -2445,8 +2594,8 @@ grpc::Status engine_impl::ChangeServiceObjectIntVar( temp_service->set_check_interval(request->dval()); attr = MODATTR_NORMAL_CHECK_INTERVAL; - /* schedule a service check if previous interval was 0 (checks were not - * regularly scheduled) */ + /* schedule a service check if previous interval was 0 (checks were + * not regularly scheduled) */ if (old_dval == 0 && temp_service->active_checks_enabled() && temp_service->check_interval() != 0) { time_t preferred_time(0); diff --git a/engine/inc/com/centreon/engine/broker.hh b/engine/inc/com/centreon/engine/broker.hh index 843c9589477..d1bececa863 100644 --- a/engine/inc/com/centreon/engine/broker.hh +++ b/engine/inc/com/centreon/engine/broker.hh @@ -25,7 +25,6 @@ #include "com/centreon/engine/commands/command.hh" #include "com/centreon/engine/comment.hh" #include "com/centreon/engine/events/timed_event.hh" -#include "com/centreon/engine/timeperiod.hh" /* Event broker options. */ #define BROKER_NOTHING 0 @@ -454,7 +453,9 @@ int broker_host_check(int type, int check_type, const char* cmdline, char* output); -void broker_host_status(int type, com::centreon::engine::host* hst); +void broker_host_status(int type, + com::centreon::engine::host* hst, + uint32_t attributes); void broker_log_data(char* data, time_t entry_time); int broker_notification_data(int type, int flags, @@ -484,7 +485,9 @@ int broker_service_check(int type, com::centreon::engine::service* svc, int check_type, const char* cmdline); -void broker_service_status(int type, com::centreon::engine::service* svc); +void broker_service_status(int type, + com::centreon::engine::service* svc, + uint32_t attributes); void broker_statechange_data(int type, int flags, int attr, diff --git a/engine/inc/com/centreon/engine/commands/command.hh b/engine/inc/com/centreon/engine/commands/command.hh index 60f39ce058c..58125cbf632 100644 --- a/engine/inc/com/centreon/engine/commands/command.hh +++ b/engine/inc/com/centreon/engine/commands/command.hh @@ -20,7 +20,6 @@ #define CCE_COMMANDS_COMMAND_HH #include "com/centreon/engine/commands/command_listener.hh" -#include "com/centreon/engine/commands/result.hh" #include "com/centreon/engine/macros/defines.hh" namespace com::centreon::engine { diff --git a/engine/inc/com/centreon/engine/commands/processing.hh b/engine/inc/com/centreon/engine/commands/processing.hh index 34152d2ead9..f5cf0036382 100644 --- a/engine/inc/com/centreon/engine/commands/processing.hh +++ b/engine/inc/com/centreon/engine/commands/processing.hh @@ -23,10 +23,7 @@ #include "com/centreon/engine/anomalydetection.hh" #include "com/centreon/engine/configuration/applier/state.hh" #include "com/centreon/engine/contact.hh" -#include "com/centreon/engine/contactgroup.hh" -#include "com/centreon/engine/host.hh" #include "com/centreon/engine/hostgroup.hh" -#include "com/centreon/engine/service.hh" #include "com/centreon/engine/servicegroup.hh" namespace com::centreon::engine { diff --git a/engine/inc/com/centreon/engine/common.hh b/engine/inc/com/centreon/engine/common.hh index 9f28ee1ac9a..6ad8003d64f 100644 --- a/engine/inc/com/centreon/engine/common.hh +++ b/engine/inc/com/centreon/engine/common.hh @@ -1,24 +1,23 @@ -/* -** Copyright 1999-2009 Ethan Galstad -** Copyright 2009-2011 Nagios Core Development Team and Community -*Contributors -** Copyright 2011-2013,2016 Centreon -** -** This file is part of Centreon Engine. -** -** Centreon Engine is free software: you can redistribute it and/or -** modify it under the terms of the GNU General Public License version 2 -** as published by the Free Software Foundation. -** -** Centreon Engine is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with Centreon Engine. If not, see -** . -*/ +/** + * Copyright 1999-2009 Ethan Galstad + * Copyright 2009-2011 Nagios Core Development Team and Community + * Contributors Copyright 2011-2013,2016, 2024 Centreon + * + * This file is part of Centreon Engine. + * + * Centreon Engine is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * Centreon Engine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Centreon Engine. If not, see + * . + */ #ifndef CCE_COMMON_HH #define CCE_COMMON_HH @@ -291,26 +290,31 @@ enum ret_val { 8192 /* Max length of an external command. */ #define MAX_DATETIME_LENGTH 48 -/* Modified attributes. */ -#define MODATTR_NONE 0 -#define MODATTR_NOTIFICATIONS_ENABLED (1 << 0) -#define MODATTR_ACTIVE_CHECKS_ENABLED (1 << 1) -#define MODATTR_PASSIVE_CHECKS_ENABLED (1 << 2) -#define MODATTR_EVENT_HANDLER_ENABLED (1 << 3) -#define MODATTR_FLAP_DETECTION_ENABLED (1 << 4) -#define MODATTR_FAILURE_PREDICTION_ENABLED (1 << 5) -#define MODATTR_PERFORMANCE_DATA_ENABLED (1 << 6) -#define MODATTR_OBSESSIVE_HANDLER_ENABLED (1 << 7) -#define MODATTR_EVENT_HANDLER_COMMAND (1 << 8) -#define MODATTR_CHECK_COMMAND (1 << 9) -#define MODATTR_NORMAL_CHECK_INTERVAL (1 << 10) -#define MODATTR_RETRY_CHECK_INTERVAL (1 << 11) -#define MODATTR_MAX_CHECK_ATTEMPTS (1 << 12) -#define MODATTR_FRESHNESS_CHECKS_ENABLED (1 << 13) -#define MODATTR_CHECK_TIMEPERIOD (1 << 14) -#define MODATTR_CUSTOM_VARIABLE (1 << 15) -#define MODATTR_NOTIFICATION_TIMEPERIOD (1 << 16) -#define MODATTR_ALL (~0u) +/* Modified attributes. These attributes are configuration attributes not real + * time ones. For example, we have a "modified attributes" field in services + * that stores them to know what has been changed in the current configuration, + * usually changed through an external command. */ +enum modattr { + MODATTR_NONE = 0, + MODATTR_NOTIFICATIONS_ENABLED = 1 << 0, + MODATTR_ACTIVE_CHECKS_ENABLED = 1 << 1, + MODATTR_PASSIVE_CHECKS_ENABLED = 1 << 2, + MODATTR_EVENT_HANDLER_ENABLED = 1 << 3, + MODATTR_FLAP_DETECTION_ENABLED = 1 << 4, + MODATTR_FAILURE_PREDICTION_ENABLED = 1 << 5, + MODATTR_PERFORMANCE_DATA_ENABLED = 1 << 6, + MODATTR_OBSESSIVE_HANDLER_ENABLED = 1 << 7, + MODATTR_EVENT_HANDLER_COMMAND = 1 << 8, + MODATTR_CHECK_COMMAND = 1 << 9, + MODATTR_NORMAL_CHECK_INTERVAL = 1 << 10, + MODATTR_RETRY_CHECK_INTERVAL = 1 << 11, + MODATTR_MAX_CHECK_ATTEMPTS = 1 << 12, + MODATTR_FRESHNESS_CHECKS_ENABLED = 1 << 13, + MODATTR_CHECK_TIMEPERIOD = 1 << 14, + MODATTR_CUSTOM_VARIABLE = 1 << 15, + MODATTR_NOTIFICATION_TIMEPERIOD = 1 << 16, + MODATTR_ALL = ~0u, +}; /* Default values. */ #define DEFAULT_ORPHAN_CHECK_INTERVAL \ diff --git a/engine/inc/com/centreon/engine/downtimes/downtime.hh b/engine/inc/com/centreon/engine/downtimes/downtime.hh index 421433e96c2..4f321f4e6e2 100644 --- a/engine/inc/com/centreon/engine/downtimes/downtime.hh +++ b/engine/inc/com/centreon/engine/downtimes/downtime.hh @@ -22,7 +22,6 @@ #define CCE_DOWNTIMES_DOWTIME_HH #include "com/centreon/engine/host.hh" -#include "com/centreon/engine/service.hh" namespace com::centreon::engine { diff --git a/engine/inc/com/centreon/engine/escalation.hh b/engine/inc/com/centreon/engine/escalation.hh index 8566fa9601a..21c997d18c4 100644 --- a/engine/inc/com/centreon/engine/escalation.hh +++ b/engine/inc/com/centreon/engine/escalation.hh @@ -18,7 +18,6 @@ #ifndef CCE_ESCALATION_HH #define CCE_ESCALATION_HH -#include "com/centreon/engine/contactgroup.hh" #include "com/centreon/engine/notifier.hh" #include "com/centreon/engine/shared.hh" diff --git a/engine/inc/com/centreon/engine/flapping.hh b/engine/inc/com/centreon/engine/flapping.hh index 601e06c700b..66ae8c29ca8 100644 --- a/engine/inc/com/centreon/engine/flapping.hh +++ b/engine/inc/com/centreon/engine/flapping.hh @@ -22,7 +22,6 @@ #define CCE_FLAPPING_HH #include "com/centreon/engine/host.hh" -#include "com/centreon/engine/service.hh" // Flapping Types #define HOST_FLAPPING 0 diff --git a/engine/inc/com/centreon/engine/globals.hh b/engine/inc/com/centreon/engine/globals.hh index 274928a6a52..03f5d47e241 100644 --- a/engine/inc/com/centreon/engine/globals.hh +++ b/engine/inc/com/centreon/engine/globals.hh @@ -32,7 +32,6 @@ #ifdef LEGACY_CONF #include "common/engine_legacy_conf/state.hh" #else -#include "common/engine_conf/state.pb.h" #endif #include "common/log_v2/log_v2.hh" diff --git a/engine/inc/com/centreon/engine/host.hh b/engine/inc/com/centreon/engine/host.hh index 20366362956..d9c00c7fb4a 100644 --- a/engine/inc/com/centreon/engine/host.hh +++ b/engine/inc/com/centreon/engine/host.hh @@ -129,7 +129,7 @@ class host : public notifier { void clear_flap(double percent_change, double high_threshold, double low_threshold); - void update_status() override; + void update_status(uint32_t attributes = STATUS_ALL) override; void update_adaptive_data(); void check_for_expired_acknowledgement(); // bool check_notification_viability(reason_type type, diff --git a/engine/inc/com/centreon/engine/macros.hh b/engine/inc/com/centreon/engine/macros.hh index f3c8d74dab9..cb16341eccf 100644 --- a/engine/inc/com/centreon/engine/macros.hh +++ b/engine/inc/com/centreon/engine/macros.hh @@ -24,7 +24,6 @@ #include "com/centreon/engine/macros/clear_hostgroup.hh" #include "com/centreon/engine/macros/clear_service.hh" #include "com/centreon/engine/macros/clear_servicegroup.hh" -#include "com/centreon/engine/macros/defines.hh" #include "com/centreon/engine/macros/grab_host.hh" #include "com/centreon/engine/macros/grab_service.hh" #include "com/centreon/engine/macros/grab_value.hh" diff --git a/engine/inc/com/centreon/engine/macros/grab_host.hh b/engine/inc/com/centreon/engine/macros/grab_host.hh index 3b81c8e7179..e926b68ccc9 100644 --- a/engine/inc/com/centreon/engine/macros/grab_host.hh +++ b/engine/inc/com/centreon/engine/macros/grab_host.hh @@ -21,7 +21,6 @@ #ifndef CCE_MACROS_GRAB_HOST_HH #define CCE_MACROS_GRAB_HOST_HH -#include "com/centreon/engine/host.hh" #include "com/centreon/engine/macros/defines.hh" #ifdef __cplusplus diff --git a/engine/inc/com/centreon/engine/macros/grab_service.hh b/engine/inc/com/centreon/engine/macros/grab_service.hh index 4435965f0cd..9ca42e20b8d 100644 --- a/engine/inc/com/centreon/engine/macros/grab_service.hh +++ b/engine/inc/com/centreon/engine/macros/grab_service.hh @@ -22,7 +22,6 @@ #define CCE_MACROS_GRAB_SERVICE_HH #include "com/centreon/engine/macros/defines.hh" -#include "com/centreon/engine/service.hh" #ifdef __cplusplus extern "C" { diff --git a/engine/inc/com/centreon/engine/nebstructs.hh b/engine/inc/com/centreon/engine/nebstructs.hh index 786e1f56b53..271aa3b53d5 100644 --- a/engine/inc/com/centreon/engine/nebstructs.hh +++ b/engine/inc/com/centreon/engine/nebstructs.hh @@ -22,8 +22,6 @@ #define CCE_NEBSTRUCTS_HH #include "com/centreon/engine/comment.hh" -#include "com/centreon/engine/host.hh" -#include "com/centreon/engine/service.hh" /* Acknowledgement structure. */ typedef struct nebstruct_acknowledgement_struct { @@ -187,6 +185,7 @@ typedef struct nebstruct_host_check_struct { typedef struct nebstruct_host_status_struct { int type; void* object_ptr; + uint32_t attributes; } nebstruct_host_status_data; /* Log data structure. */ @@ -248,6 +247,7 @@ typedef struct nebstruct_service_check_struct { typedef struct nebstruct_service_status_struct { int type; void* object_ptr; + uint32_t attributes; } nebstruct_service_status_data; typedef struct nebstruct_bench_struct { diff --git a/engine/inc/com/centreon/engine/notifier.hh b/engine/inc/com/centreon/engine/notifier.hh index 8705f069bbb..b35f0c67383 100644 --- a/engine/inc/com/centreon/engine/notifier.hh +++ b/engine/inc/com/centreon/engine/notifier.hh @@ -1,5 +1,5 @@ /* - * Copyright 2019 Centreon (https://www.centreon.com/) + * Copyright 2019-2024 Centreon (https://www.centreon.com/) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,6 +39,15 @@ using AckType = com::centreon::broker::AckType; class notifier : public checkable { public: + /* Status attributes. Used as argument in the notifier::update_status(). */ + enum status_attribute { + STATUS_NONE = 0, + STATUS_DOWNTIME_DEPTH = 1 << 0, + STATUS_NOTIFICATION_NUMBER = 1 << 1, + STATUS_ACKNOWLEDGEMENT = 1 << 2, + STATUS_ALL = ~0u, + }; + enum notification_category { cat_normal, cat_recovery, @@ -173,7 +182,14 @@ class notifier : public checkable { virtual bool schedule_check(time_t check_time, uint32_t options, bool no_update_status_now) = 0; - virtual void update_status() = 0; + + /** + * @brief Update the status of the notifier partially. attributes is a bits + * field based on enum status_attribute specifying what has to be updated. + * + * @param attributes A bits field based on enum status_attribute. + */ + virtual void update_status(uint32_t attributes) = 0; int notify(reason_type type, std::string const& not_author, std::string const& not_data, diff --git a/engine/inc/com/centreon/engine/objects.hh b/engine/inc/com/centreon/engine/objects.hh index a206ba72d5c..79ad67e538c 100644 --- a/engine/inc/com/centreon/engine/objects.hh +++ b/engine/inc/com/centreon/engine/objects.hh @@ -22,13 +22,11 @@ #define CCE_OBJECTS_HH #include "com/centreon/engine/anomalydetection.hh" #include "com/centreon/engine/comment.hh" -#include "com/centreon/engine/daterange.hh" #include "com/centreon/engine/downtimes/downtime.hh" #include "com/centreon/engine/hostdependency.hh" #include "com/centreon/engine/hostescalation.hh" #include "com/centreon/engine/hostgroup.hh" #include "com/centreon/engine/servicedependency.hh" #include "com/centreon/engine/serviceescalation.hh" -#include "com/centreon/engine/timerange.hh" #endif /* !CCE_OBJECTS_HH */ diff --git a/engine/inc/com/centreon/engine/sehandlers.hh b/engine/inc/com/centreon/engine/sehandlers.hh index e1086bcb160..d3e28d58505 100644 --- a/engine/inc/com/centreon/engine/sehandlers.hh +++ b/engine/inc/com/centreon/engine/sehandlers.hh @@ -21,9 +21,7 @@ #ifndef CCE_SEHANDLERS_HH #define CCE_SEHANDLERS_HH -#include "com/centreon/engine/host.hh" #include "com/centreon/engine/macros/defines.hh" -#include "com/centreon/engine/service.hh" // Event Handler Types #define HOST_EVENTHANDLER 0 diff --git a/engine/inc/com/centreon/engine/service.hh b/engine/inc/com/centreon/engine/service.hh index a6b4d84ee44..25874da44d2 100644 --- a/engine/inc/com/centreon/engine/service.hh +++ b/engine/inc/com/centreon/engine/service.hh @@ -20,7 +20,6 @@ #define CCE_SERVICE_HH #include "com/centreon/engine/check_result.hh" -#include "com/centreon/engine/common.hh" #include "com/centreon/engine/hash.hh" #include "com/centreon/engine/logging.hh" #include "com/centreon/engine/notifier.hh" @@ -218,7 +217,7 @@ class service : public notifier { double low_threshold); void enable_flap_detection(); void disable_flap_detection(); - void update_status() override; + void update_status(uint32_t status_attributes = STATUS_ALL) override; void update_adaptive_data(); bool verify_check_viability(int check_options, bool* time_is_valid, diff --git a/engine/inc/com/centreon/engine/statusdata.hh b/engine/inc/com/centreon/engine/statusdata.hh index a94aec5c457..e3d32f2e876 100644 --- a/engine/inc/com/centreon/engine/statusdata.hh +++ b/engine/inc/com/centreon/engine/statusdata.hh @@ -22,7 +22,6 @@ #define CCE_STATUSDATA_HH #include "com/centreon/engine/host.hh" -#include "com/centreon/engine/service.hh" #ifdef __cplusplus extern "C" { diff --git a/engine/inc/com/centreon/engine/utils.hh b/engine/inc/com/centreon/engine/utils.hh index 7560738d8b0..98145eae250 100644 --- a/engine/inc/com/centreon/engine/utils.hh +++ b/engine/inc/com/centreon/engine/utils.hh @@ -21,8 +21,6 @@ #ifndef CCE_UTILS_HH #define CCE_UTILS_HH -#include "com/centreon/engine/check_result.hh" -#include "com/centreon/engine/daterange.hh" #include "com/centreon/engine/macros/defines.hh" #ifdef __cplusplus diff --git a/engine/modules/bench/CMakeLists.txt b/engine/modules/bench/CMakeLists.txt index 8f270f2d357..147239d7381 100644 --- a/engine/modules/bench/CMakeLists.txt +++ b/engine/modules/bench/CMakeLists.txt @@ -37,12 +37,12 @@ if (WITH_BENCH) COMPONENT "bench") # Passive checks benchmarking command line tool. - add_executable("centengine_bench_passive" - "${SRC_DIR}/passive/engine_cfg.cc" - "${SRC_DIR}/passive/main.cc") - add_dependencies("centengine_bench_passive" centreon_clib) - target_link_libraries("centengine_bench_passive" centreon_clib fmt::fmt) - target_precompile_headers("centengine_bench_passive" PRIVATE ../../precomp_inc/precomp.hh) + add_executable(centengine_bench_passive + ${SRC_DIR}/passive/engine_cfg.cc + ${SRC_DIR}/passive/main.cc) + add_dependencies(centengine_bench_passive centreon_clib) + target_link_libraries(centengine_bench_passive centreon_clib fmt::fmt) + target_precompile_headers(centengine_bench_passive PRIVATE ../../precomp_inc/precomp.hh) install(TARGETS "centengine_bench_passive" DESTINATION "${CMAKE_INSTALL_FULL_SBINDIR}" diff --git a/engine/modules/opentelemetry/doc/opentelemetry.md b/engine/modules/opentelemetry/doc/opentelemetry.md index 73568749bb3..f83f8bb24c9 100644 --- a/engine/modules/opentelemetry/doc/opentelemetry.md +++ b/engine/modules/opentelemetry/doc/opentelemetry.md @@ -190,8 +190,8 @@ An example of configuration: "http_server" : { "port": 1443, "encryption": true, - "certificate_path": "server.crt", - "key_path": "server.key" + "public_cert": "server.crt", + "private_key": "server.key" }, "engine_otel_endpoint": "172.17.0.1:4317", "check_interval":60 diff --git a/engine/modules/opentelemetry/doc/otel_configuration.odg b/engine/modules/opentelemetry/doc/otel_configuration.odg index c14e698328b..14831418dac 100644 Binary files a/engine/modules/opentelemetry/doc/otel_configuration.odg and b/engine/modules/opentelemetry/doc/otel_configuration.odg differ diff --git a/engine/modules/opentelemetry/doc/otel_configuration.pdf b/engine/modules/opentelemetry/doc/otel_configuration.pdf index 3bff7928002..10105d81fca 100644 Binary files a/engine/modules/opentelemetry/doc/otel_configuration.pdf and b/engine/modules/opentelemetry/doc/otel_configuration.pdf differ diff --git a/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/centreon_agent/agent_impl.hh b/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/centreon_agent/agent_impl.hh index 41d63ac029c..c1e1a4a5c06 100644 --- a/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/centreon_agent/agent_impl.hh +++ b/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/centreon_agent/agent_impl.hh @@ -23,6 +23,8 @@ #include "com/centreon/engine/modules/opentelemetry/centreon_agent/agent_config.hh" #include "com/centreon/engine/modules/opentelemetry/otl_data_point.hh" +#include "com/centreon/engine/modules/opentelemetry/conf_helper.hh" + namespace com::centreon::engine::modules::opentelemetry::centreon_agent { /** @@ -38,6 +40,8 @@ class agent_impl std::shared_ptr _io_context; const std::string_view _class_name; + whitelist_cache _whitelist_cache; + agent_config::pointer _conf ABSL_GUARDED_BY(_protect); metric_handler _metric_handler; diff --git a/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/conf_helper.hh b/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/conf_helper.hh index a2bbb242c08..a2e7b1cc6dc 100644 --- a/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/conf_helper.hh +++ b/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/conf_helper.hh @@ -18,6 +18,8 @@ #ifndef CCE_MOD_CONF_HELPER_OPENTELEMETRY_HH #define CCE_MOD_CONF_HELPER_OPENTELEMETRY_HH +#include +#include "com/centreon/engine/configuration/whitelist.hh" #include "com/centreon/engine/host.hh" #include "com/centreon/engine/macros.hh" #include "com/centreon/engine/service.hh" @@ -26,6 +28,16 @@ namespace com::centreon::engine::modules::opentelemetry { +/** + * @brief in this struct we store results of whitelist approvals + * + */ +struct whitelist_cache { + using cache = absl::flat_hash_map; + uint whitelist_instance_id; + cache data; +}; + /** * @brief extract opentelemetry commands from an host list * This function must be called from engine main thread, not grpc ones @@ -39,6 +51,7 @@ namespace com::centreon::engine::modules::opentelemetry { template bool get_otel_commands(const std::string& host_name, command_handler&& handler, + whitelist_cache& whitelist_cache, const std::shared_ptr& logger) { auto use_otl_command = [](const checkable& to_test) -> bool { if (to_test.get_check_command_ptr()) { @@ -56,6 +69,24 @@ bool get_otel_commands(const std::string& host_name, return false; }; + configuration::whitelist& wchecker = configuration::whitelist::instance(); + + auto allowed_by_white_list = [&](const std::string& cmd_line) { + auto cache_iter = whitelist_cache.data.find(cmd_line); + if (cache_iter != whitelist_cache.data.end()) { + return cache_iter->second; + } + bool allowed = wchecker.is_allowed(cmd_line); + + whitelist_cache.data.emplace(cmd_line, allowed); + return allowed; + }; + + if (wchecker.instance_id() != whitelist_cache.whitelist_instance_id) { + whitelist_cache.whitelist_instance_id = wchecker.instance_id(); + whitelist_cache.data.clear(); + } + bool ret = false; auto hst_iter = host::hosts.find(host_name); @@ -68,10 +99,22 @@ bool get_otel_commands(const std::string& host_name, // host check use otl? if (use_otl_command(*hst)) { nagios_macros* macros(get_global_macros()); - - ret |= handler(hst->check_command(), hst->get_check_command_line(macros), - "", logger); + cmd_line = hst->get_check_command_line(macros); clear_volatile_macros_r(macros); + + if (allowed_by_white_list(cmd_line)) { + ret |= handler(hst->check_command(), cmd_line, "", logger); + } else { + SPDLOG_LOGGER_ERROR( + logger, + "host {}: this command cannot be executed because of " + "security restrictions on the poller. A whitelist has " + "been defined, and it does not include this command.", + host_name); + SPDLOG_LOGGER_DEBUG(logger, + "host {}: command not allowed by whitelist {}", + host_name, cmd_line); + } } else { SPDLOG_LOGGER_DEBUG( logger, "host {} doesn't use opentelemetry to do his check", host_name); @@ -84,10 +127,23 @@ bool get_otel_commands(const std::string& host_name, std::shared_ptr serv = serv_iter->second; if (use_otl_command(*serv)) { nagios_macros* macros(get_global_macros()); - ret |= - handler(serv->check_command(), serv->get_check_command_line(macros), - serv->name(), logger); + cmd_line = serv->get_check_command_line(macros); clear_volatile_macros_r(macros); + + if (allowed_by_white_list(cmd_line)) { + ret |= handler(serv->check_command(), cmd_line, serv->name(), logger); + } else { + SPDLOG_LOGGER_ERROR( + logger, + "service {}: this command cannot be executed because of " + "security restrictions on the poller. A whitelist has " + "been defined, and it does not include this command.", + serv->name()); + + SPDLOG_LOGGER_DEBUG(logger, + "service {}: command not allowed by whitelist {}", + serv->name(), cmd_line); + } } else { SPDLOG_LOGGER_DEBUG( logger, diff --git a/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/telegraf/conf_server.hh b/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/telegraf/conf_server.hh index 989af594b33..bc6430624a8 100644 --- a/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/telegraf/conf_server.hh +++ b/engine/modules/opentelemetry/inc/com/centreon/engine/modules/opentelemetry/telegraf/conf_server.hh @@ -31,9 +31,8 @@ class conf_server_config { asio::ip::tcp::endpoint _listen_endpoint; bool _crypted; unsigned _second_keep_alive_interval; - std::string _certificate_path; - std::string _key_path; - std::string _engine_otl_endpoint; + std::string _public_cert; + std::string _private_key; unsigned _check_interval; public: @@ -52,11 +51,8 @@ class conf_server_config { unsigned get_check_interval() const { return _check_interval; } - const std::string& get_certificate_path() const { return _certificate_path; } - const std::string& get_key_path() const { return _key_path; } - const std::string& get_engine_otl_endpoint() const { - return _engine_otl_endpoint; - } + const std::string& get_public_cert() const { return _public_cert; } + const std::string& get_private_key() const { return _private_key; } bool operator==(const conf_server_config& right) const; }; @@ -77,8 +73,6 @@ class conf_session : public connection_class { void answer_to_request(const std::shared_ptr& request, const std::string& host); - bool _get_commands(const std::string& host_name, std::string& request_body); - bool _otel_connector_to_stream(const std::string& cmd_name, const std::string& cmd_line, const std::string& host, diff --git a/engine/modules/opentelemetry/src/centreon_agent/agent_impl.cc b/engine/modules/opentelemetry/src/centreon_agent/agent_impl.cc index 5db31e4c877..2514549e998 100644 --- a/engine/modules/opentelemetry/src/centreon_agent/agent_impl.cc +++ b/engine/modules/opentelemetry/src/centreon_agent/agent_impl.cc @@ -20,7 +20,6 @@ #include "centreon_agent/agent_impl.hh" -#include "conf_helper.hh" #include "otl_fmt.hh" #include "com/centreon/engine/command_manager.hh" @@ -179,7 +178,7 @@ void agent_impl::_calc_and_send_config_if_needed() { return add_command_to_agent_conf(cmd_name, cmd_line, service, cnf, logger, peer); }, - _logger); + _whitelist_cache, _logger); if (!at_least_one_command_found) { SPDLOG_LOGGER_ERROR(_logger, "no command found for agent {}", get_peer()); @@ -443,4 +442,4 @@ template class agent_impl< template class agent_impl< ::grpc::ServerBidiReactor>; -} // namespace com::centreon::engine::modules::opentelemetry::centreon_agent \ No newline at end of file +} // namespace com::centreon::engine::modules::opentelemetry::centreon_agent diff --git a/engine/modules/opentelemetry/src/open_telemetry.cc b/engine/modules/opentelemetry/src/open_telemetry.cc index 776cecfba11..1e8e6cdcdef 100644 --- a/engine/modules/opentelemetry/src/open_telemetry.cc +++ b/engine/modules/opentelemetry/src/open_telemetry.cc @@ -182,7 +182,7 @@ void open_telemetry::_create_telegraf_conf_server( std::chrono::seconds(10), std::chrono::seconds(30), std::chrono::seconds(300), 30, std::chrono::seconds(10), 0, std::chrono::hours(1), 1, asio::ssl::context::tlsv12, - telegraf_conf->get_certificate_path(), telegraf_conf->get_key_path()); + telegraf_conf->get_public_cert(), telegraf_conf->get_private_key()); if (telegraf_conf->is_crypted()) { _telegraf_conf_server = http::server::load( diff --git a/engine/modules/opentelemetry/src/telegraf/conf_server.cc b/engine/modules/opentelemetry/src/telegraf/conf_server.cc index d6e4d720571..d38e8e3034e 100644 --- a/engine/modules/opentelemetry/src/telegraf/conf_server.cc +++ b/engine/modules/opentelemetry/src/telegraf/conf_server.cc @@ -62,12 +62,12 @@ static constexpr std::string_view _config_schema(R"( "minimum": 0, "maximum": 3600 }, - "certificate_path": { + "public_cert": { "description": "path of the certificate file of the server", "type": "string", "minLength": 5 }, - "key_path": { + "private_key": { "description": "path of the key file", "type": "string", "minLength": 5 @@ -77,16 +77,8 @@ static constexpr std::string_view _config_schema(R"( "description": "interval in seconds between two checks (param [agent] interval) ", "type": "integer", "minimum": 10 - }, - "engine_otel_endpoint": { - "description": "opentelemetry engine grpc server", - "type": "string", - "minLength": 5 } }, - "required":[ - "engine_otel_endpoint" - ], "type": "object" } )"); @@ -105,7 +97,6 @@ conf_server_config::conf_server_config(const rapidjson::Value& json_config_v, throw; } - _engine_otl_endpoint = json_config.get_string("engine_otel_endpoint"); _check_interval = json_config.get_unsigned("check_interval", 60); if (json_config_v.HasMember("http_server")) { @@ -131,10 +122,10 @@ conf_server_config::conf_server_config(const rapidjson::Value& json_config_v, _second_keep_alive_interval = http_json_config.get_unsigned("keepalive_interval", 30); - _certificate_path = http_json_config.get_string("certificate_path", ""); - _key_path = http_json_config.get_string("key_path", ""); + _public_cert = http_json_config.get_string("public_cert", ""); + _private_key = http_json_config.get_string("private_key", ""); if (_crypted) { - if (_certificate_path.empty()) { + if (_public_cert.empty()) { SPDLOG_LOGGER_ERROR(config_logger, "telegraf conf server encryption activated and no " "certificate path " @@ -144,7 +135,7 @@ conf_server_config::conf_server_config(const rapidjson::Value& json_config_v, "path " "provided"); } - if (_key_path.empty()) { + if (_private_key.empty()) { SPDLOG_LOGGER_ERROR(config_logger, "telegraf conf server encryption activated and no " "certificate key path provided"); @@ -153,23 +144,23 @@ conf_server_config::conf_server_config(const rapidjson::Value& json_config_v, "telegraf conf server encryption activated and no certificate key " "path provided"); } - if (::access(_certificate_path.c_str(), R_OK)) { + if (::access(_public_cert.c_str(), R_OK)) { SPDLOG_LOGGER_ERROR( config_logger, "telegraf conf server unable to read certificate file {}", - _certificate_path); + _public_cert); throw exceptions::msg_fmt( "telegraf conf server unable to read certificate file {}", - _certificate_path); + _public_cert); } - if (::access(_key_path.c_str(), R_OK)) { + if (::access(_private_key.c_str(), R_OK)) { SPDLOG_LOGGER_ERROR( config_logger, "telegraf conf server unable to read certificate key file {}", - _key_path); + _private_key); throw exceptions::msg_fmt( "telegraf conf server unable to read certificate key file {}", - _key_path); + _private_key); } } } else { @@ -184,8 +175,8 @@ bool conf_server_config::operator==(const conf_server_config& right) const { return _listen_endpoint == right._listen_endpoint && _crypted == right._crypted && _second_keep_alive_interval == right._second_keep_alive_interval && - _certificate_path == right._certificate_path && - _key_path == right._key_path && + _public_cert == right._public_cert && + _private_key == right._private_key && _check_interval == right._check_interval; } @@ -303,76 +294,6 @@ bool conf_session::_otel_connector_to_stream( return true; } -/** - * @brief Get all opentelemetry commands from an host and add its to - * configuration response - * - * @param host - * @param request_body conf to append - * @return true at least one opentelemetry command was found - * @return false - */ -template -bool conf_session::_get_commands(const std::string& host_name, - std::string& request_body) { - auto use_otl_command = [](const checkable& to_test) -> bool { - if (to_test.get_check_command_ptr()->get_type() == - commands::command::e_type::otel) - return true; - if (to_test.get_check_command_ptr()->get_type() == - commands::command::e_type::forward) { - return std::static_pointer_cast( - to_test.get_check_command_ptr()) - ->get_sub_command() - ->get_type() == commands::command::e_type::otel; - } - return false; - }; - - bool ret = false; - auto hst_iter = host::hosts.find(host_name); - if (hst_iter == host::hosts.end()) { - SPDLOG_LOGGER_ERROR(this->_logger, "unknown host:{}", host_name); - return false; - } - std::shared_ptr hst = hst_iter->second; - std::string cmd_line; - // host check use otl? - if (use_otl_command(*hst)) { - nagios_macros* macros(get_global_macros()); - - ret |= _otel_connector_to_stream(hst->check_command(), - hst->get_check_command_line(macros), - hst->name(), "", request_body); - clear_volatile_macros_r(macros); - } else { - SPDLOG_LOGGER_DEBUG(this->_logger, - "host {} doesn't use telegraf to do his check", - host_name); - } - - // services of host - auto serv_iter = service::services_by_id.lower_bound({hst->host_id(), 0}); - for (; serv_iter != service::services_by_id.end() && - serv_iter->first.first == hst->host_id(); - ++serv_iter) { - std::shared_ptr serv = serv_iter->second; - if (use_otl_command(*serv)) { - nagios_macros* macros(get_global_macros()); - ret |= _otel_connector_to_stream( - serv->check_command(), serv->get_check_command_line(macros), - serv->get_hostname(), serv->name(), request_body); - clear_volatile_macros_r(macros); - } else { - SPDLOG_LOGGER_DEBUG( - this->_logger, - "host {} service {} doesn't use telegraf to do his check", host_name, - serv->name()); - } - } - return ret; -} - /** * @brief construct and send conf to telegraf * As it uses host, services and command list, it must be called in the main @@ -396,13 +317,22 @@ void conf_session::answer_to_request( ## Default data collection interval for all inputs interval = "{}s" -[[outputs.opentelemetry]] - service_address = "{}" - )", - _telegraf_conf->get_check_interval(), - _telegraf_conf->get_engine_otl_endpoint()); - bool at_least_one_found = _get_commands(host, resp->body()); + _telegraf_conf->get_check_interval()); + + whitelist_cache wcache; + + bool at_least_one_found = get_otel_commands( + host, + [this, &resp, &host](const std::string& cmd_name, + const std::string& cmd_line, + const std::string& service, + const std::shared_ptr& logger) { + return _otel_connector_to_stream(cmd_name, cmd_line, host, service, + resp->body()); + }, + wcache, this->_logger); + if (at_least_one_found) { resp->result(boost::beast::http::status::ok); resp->insert(boost::beast::http::field::content_type, "text/plain"); diff --git a/engine/src/anomalydetection.cc b/engine/src/anomalydetection.cc index df1a6956e69..1227881cf25 100644 --- a/engine/src/anomalydetection.cc +++ b/engine/src/anomalydetection.cc @@ -30,7 +30,6 @@ #include "com/centreon/engine/macros/grab_service.hh" #include "com/centreon/engine/neberrors.hh" #include "com/centreon/engine/string.hh" -#include "com/centreon/exceptions/interruption.hh" using namespace com::centreon::engine; diff --git a/engine/src/broker.cc b/engine/src/broker.cc index 8b5ae22dab3..a382422ee1b 100644 --- a/engine/src/broker.cc +++ b/engine/src/broker.cc @@ -742,8 +742,9 @@ int broker_host_check(int type, * * @param[in] type Type. * @param[in] hst Host. + * @param[in] attributes Attributes from status_attribute enumeration. */ -void broker_host_status(int type, host* hst) { +void broker_host_status(int type, host* hst, uint32_t attributes) { // Config check. #ifdef LEGACY_CONF if (!(config->event_broker_options() & BROKER_STATUS_DATA)) @@ -757,6 +758,7 @@ void broker_host_status(int type, host* hst) { nebstruct_host_status_data ds; ds.type = type; ds.object_ptr = hst; + ds.attributes = attributes; // Make callbacks. neb_make_callbacks(NEBCALLBACK_HOST_STATUS_DATA, &ds); @@ -998,8 +1000,11 @@ int broker_service_check(int type, * * @param[in] type Type. * @param[in] svc Target service. + * @param[in] attributes Attributes from status_attribute enumeration. */ -void broker_service_status(int type, com::centreon::engine::service* svc) { +void broker_service_status(int type, + com::centreon::engine::service* svc, + uint32_t attributes) { // Config check. #ifdef LEGACY_CONF if (!(config->event_broker_options() & BROKER_STATUS_DATA)) @@ -1013,6 +1018,7 @@ void broker_service_status(int type, com::centreon::engine::service* svc) { nebstruct_service_status_data ds; ds.type = type; ds.object_ptr = svc; + ds.attributes = attributes; // Make callbacks. neb_make_callbacks(NEBCALLBACK_SERVICE_STATUS_DATA, &ds); diff --git a/engine/src/centenginestats.cc b/engine/src/centenginestats.cc index 02ceff82345..155a45f8b0b 100644 --- a/engine/src/centenginestats.cc +++ b/engine/src/centenginestats.cc @@ -27,9 +27,10 @@ #include "com/centreon/engine/objects.hh" #include "com/centreon/engine/string.hh" #include "com/centreon/engine/version.hh" -#include "com/centreon/exceptions/basic.hh" +#include "com/centreon/exceptions/msg_fmt.hh" using namespace com::centreon::engine; +using com::centreon::exceptions::msg_fmt; #define STATUS_NO_DATA 0 #define STATUS_INFO_DATA 1 @@ -324,22 +325,19 @@ int main(int argc, char* argv[]) { if (stats_file) { if (read_stats_file() == ERROR) { char const* msg(strerror(errno)); - throw(basic_error() - << "Error reading stats file '" << stats_file << "': " << msg); + throw msg_fmt("Error reading stats file '{}': {}", stats_file, msg); } } // Else read the normal status file. else { // Read main config file. if (read_config_file() == ERROR) - throw(basic_error() - << "Error processing config file '" << main_config_file); + throw msg_fmt("Error processing config file '{}'", main_config_file); // Read status file. if (read_status_file() == ERROR) { char const* msg(strerror(errno)); - throw(basic_error() << "Error reading status file '" << status_file - << "': " << msg); + throw msg_fmt("Error reading status file '{}': {}", status_file, msg); } } diff --git a/engine/src/checks/checker.cc b/engine/src/checks/checker.cc index 235d9ff63e4..3b83727b5a4 100644 --- a/engine/src/checks/checker.cc +++ b/engine/src/checks/checker.cc @@ -1,22 +1,22 @@ /** -* Copyright 1999-2010 Ethan Galstad -* Copyright 2011-2024 Centreon -* -* This file is part of Centreon Engine. -* -* Centreon Engine is free software: you can redistribute it and/or -* modify it under the terms of the GNU General Public License version 2 -* as published by the Free Software Foundation. -* -* Centreon Engine is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with Centreon Engine. If not, see -* . -*/ + * Copyright 1999-2010 Ethan Galstad + * Copyright 2011-2024 Centreon + * + * This file is part of Centreon Engine. + * + * Centreon Engine is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * Centreon Engine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Centreon Engine. If not, see + * . + */ #include "com/centreon/engine/checks/checker.hh" @@ -31,7 +31,6 @@ #include "com/centreon/engine/objects.hh" #include "com/centreon/engine/shared.hh" #include "com/centreon/engine/string.hh" -#include "com/centreon/exceptions/interruption.hh" using namespace com::centreon; using namespace com::centreon::engine::logging; @@ -600,9 +599,9 @@ com::centreon::engine::host::host_state checker::_execute_sync(host* hst) { // If the command timed out. #ifdef LEGACY_CONF -uint32_t host_check_timeout = config->host_check_timeout(); + uint32_t host_check_timeout = config->host_check_timeout(); #else -uint32_t host_check_timeout = pb_config.host_check_timeout(); + uint32_t host_check_timeout = pb_config.host_check_timeout(); #endif if (res.exit_status == process::timeout) { res.output = fmt::format("Host check timed out after {} seconds", diff --git a/engine/src/commands/commands.cc b/engine/src/commands/commands.cc index 072e14870d4..b0feacaf58f 100644 --- a/engine/src/commands/commands.cc +++ b/engine/src/commands/commands.cc @@ -1,6 +1,6 @@ /** * Copyright 1999-2008 Ethan Galstad - * Copyright 2011-2013,2015-2022 Centreon + * Copyright 2011-2013,2015-2024 Centreon * * This file is part of Centreon Engine. * @@ -26,9 +26,7 @@ #include "com/centreon/engine/broker.hh" #include "com/centreon/engine/checks/checker.hh" #include "com/centreon/engine/commands/processing.hh" -#include "com/centreon/engine/comment.hh" -#include "com/centreon/engine/configuration/applier/state.hh" -#include "com/centreon/engine/downtimes/downtime.hh" +#include "com/centreon/engine/common.hh" #include "com/centreon/engine/downtimes/downtime_finder.hh" #include "com/centreon/engine/downtimes/downtime_manager.hh" #include "com/centreon/engine/events/loop.hh" @@ -553,8 +551,7 @@ int cmd_process_service_check_result(int cmd [[maybe_unused]], runtime_logger->warn( "Warning: Passive check result was received for service '{}' on host " "'{}', but the host could not be found!", - fmt::string_view(svc_description.data(), svc_description.size()), - fmt::string_view(host_name.data(), host_name.size())); + svc_description, host_name); return ERROR; } @@ -2678,7 +2675,7 @@ void acknowledge_host_problem(host* hst, notifier::notification_option_none); /* update the status log with the host info */ - hst->update_status(); + hst->update_status(host::STATUS_ACKNOWLEDGEMENT); /* add a comment for the acknowledgement */ auto com{std::make_shared( @@ -2719,7 +2716,7 @@ void acknowledge_service_problem(service* svc, notifier::notification_option_none); /* update the status log with the service info */ - svc->update_status(); + svc->update_status(service::STATUS_ACKNOWLEDGEMENT); /* add a comment for the acknowledgement */ auto com{std::make_shared( @@ -2735,7 +2732,7 @@ void remove_host_acknowledgement(host* hst) { hst->set_acknowledgement(AckType::NONE); /* update the status log with the host info */ - hst->update_status(); + hst->update_status(host::STATUS_ACKNOWLEDGEMENT); /* remove any non-persistant comments associated with the ack */ comment::delete_host_acknowledgement_comments(hst); @@ -2747,7 +2744,7 @@ void remove_service_acknowledgement(service* svc) { svc->set_acknowledgement(AckType::NONE); /* update the status log with the service info */ - svc->update_status(); + svc->update_status(host::STATUS_ACKNOWLEDGEMENT); /* remove any non-persistant comments associated with the ack */ comment::delete_service_acknowledgement_comments(svc); @@ -2863,7 +2860,8 @@ void stop_accepting_passive_service_checks(void) { #ifdef LEGACY_CONF bool accept_passive_service_checks = config->accept_passive_service_checks(); #else - bool accept_passive_service_checks = pb_config.accept_passive_service_checks(); + bool accept_passive_service_checks = + pb_config.accept_passive_service_checks(); #endif /* bail out if we're already not accepting passive services */ diff --git a/engine/src/downtimes/host_downtime.cc b/engine/src/downtimes/host_downtime.cc index f594e558b7d..65b499fb32a 100644 --- a/engine/src/downtimes/host_downtime.cc +++ b/engine/src/downtimes/host_downtime.cc @@ -1,5 +1,5 @@ /** - * Copyright 2019 Centreon (https://www.centreon.com/) + * Copyright 2019-2024 Centreon (https://www.centreon.com/) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,7 +19,7 @@ #include "com/centreon/engine/downtimes/host_downtime.hh" #include "com/centreon/engine/broker.hh" -#include "com/centreon/engine/comment.hh" +#include "com/centreon/engine/common.hh" #include "com/centreon/engine/configuration/applier/state.hh" #include "com/centreon/engine/downtimes/downtime_manager.hh" #include "com/centreon/engine/events/loop.hh" @@ -468,7 +468,7 @@ int host_downtime::handle() { /* update the status data */ /* Because of the notification the status is sent with CHECK_RESULT level */ - it_hst->second->update_status(); + it_hst->second->update_status(host::STATUS_DOWNTIME_DEPTH); /* schedule an event */ if (!is_fixed()) diff --git a/engine/src/downtimes/service_downtime.cc b/engine/src/downtimes/service_downtime.cc index d5e1671e9dd..93c4e2ac093 100644 --- a/engine/src/downtimes/service_downtime.cc +++ b/engine/src/downtimes/service_downtime.cc @@ -20,7 +20,7 @@ #include "com/centreon/engine/downtimes/service_downtime.hh" #include "com/centreon/engine/broker.hh" -#include "com/centreon/engine/comment.hh" +#include "com/centreon/engine/common.hh" #include "com/centreon/engine/configuration/applier/state.hh" #include "com/centreon/engine/downtimes/downtime_manager.hh" #include "com/centreon/engine/events/loop.hh" @@ -186,7 +186,7 @@ int service_downtime::unschedule() { get_triggered_by(), get_duration(), get_downtime_id(), nullptr); found->second->dec_scheduled_downtime_depth(); - found->second->update_status(); + found->second->update_status(service::STATUS_DOWNTIME_DEPTH); /* log a notice - this is parsed by the history CGI */ if (found->second->get_scheduled_downtime_depth() == 0) { @@ -485,8 +485,7 @@ int service_downtime::handle() { SPDLOG_LOGGER_INFO( events_logger, "SERVICE DOWNTIME ALERT: {};{};STARTED; Service has entered a period " - "of scheduled " - "downtime", + "of scheduled downtime", found->second->get_hostname(), found->second->description()); /* send a notification */ @@ -502,7 +501,7 @@ int service_downtime::handle() { /* update the status data */ /* Because of the notification the status is sent with CHECK_RESULT level */ - found->second->update_status(); + found->second->update_status(service::STATUS_DOWNTIME_DEPTH); /* schedule an event */ if (!is_fixed()) diff --git a/engine/src/events/loop.cc b/engine/src/events/loop.cc index 20500f7a155..7f99df26f35 100644 --- a/engine/src/events/loop.cc +++ b/engine/src/events/loop.cc @@ -2,7 +2,7 @@ * Copyright 1999-2009 Ethan Galstad * Copyright 2009-2010 Nagios Core Development Team and Community Contributors * Copyright 2011-2013 Merethis - * Copyright 2013-2022 Centreon + * Copyright 2013-2024 Centreon * * This file is part of Centreon Engine. * @@ -21,9 +21,7 @@ */ #include "com/centreon/engine/events/loop.hh" -#include #include -#include #include "com/centreon/engine/broker.hh" #include "com/centreon/engine/command_manager.hh" #include "com/centreon/engine/configuration/applier/state.hh" @@ -31,7 +29,6 @@ #include "com/centreon/engine/globals.hh" #include "com/centreon/engine/logging/logger.hh" #include "com/centreon/engine/statusdata.hh" -#include "com/centreon/logging/engine.hh" #ifdef LEGACY_CONF #include "common/engine_legacy_conf/parser.hh" #else @@ -373,7 +370,7 @@ void loop::_dispatching() { else temp_service->set_next_check( (time_t)(temp_service->get_next_check() + - (temp_service->check_interval() * interval_length))); + temp_service->check_interval() * interval_length)); } temp_event->run_time = temp_service->get_next_check(); reschedule_event(std::move(temp_event), events::loop::low); diff --git a/engine/src/host.cc b/engine/src/host.cc index f8a374ca624..f3d48bcd95a 100644 --- a/engine/src/host.cc +++ b/engine/src/host.cc @@ -16,14 +16,13 @@ * For more information : contact@centreon.com */ -#include "com/centreon/engine/host.hh" #include #include #include "com/centreon/engine/broker.hh" -#include "com/centreon/engine/checkable.hh" #include "com/centreon/engine/checks/checker.hh" +#include "com/centreon/engine/common.hh" #include "com/centreon/engine/configuration/applier/state.hh" #include "com/centreon/engine/configuration/whitelist.hh" #include "com/centreon/engine/downtimes/downtime_manager.hh" @@ -31,19 +30,15 @@ #include "com/centreon/engine/exceptions/error.hh" #include "com/centreon/engine/flapping.hh" #include "com/centreon/engine/globals.hh" -#include "com/centreon/engine/logging.hh" #include "com/centreon/engine/logging/logger.hh" #include "com/centreon/engine/macros.hh" -#include "com/centreon/engine/macros/grab_host.hh" #include "com/centreon/engine/neberrors.hh" #include "com/centreon/engine/notification.hh" #include "com/centreon/engine/objects.hh" #include "com/centreon/engine/sehandlers.hh" -#include "com/centreon/engine/shared.hh" #include "com/centreon/engine/statusdata.hh" #include "com/centreon/engine/string.hh" #include "com/centreon/engine/timezone_locker.hh" -#include "com/centreon/exceptions/interruption.hh" using namespace com::centreon; using namespace com::centreon::engine; @@ -1878,8 +1873,6 @@ int host::run_async_check(int check_options, // Run command. get_check_command_ptr()->run(processed_cmd, *macros, host_check_timeout, check_result_info); - } catch (com::centreon::exceptions::interruption const& e) { - retry = true; } catch (std::exception const& e) { // Update check result. run_failure("(Execute command failed)"); @@ -2322,9 +2315,12 @@ void host::clear_flap(double percent_change, /** * @brief Updates host status info. Data are sent to event broker. + * + * @param attributes A bits field based on status_attribute enum (default value: + * STATUS_ALL). */ -void host::update_status() { - broker_host_status(NEBTYPE_HOSTSTATUS_UPDATE, this); +void host::update_status(uint32_t attributes) { + broker_host_status(NEBTYPE_HOSTSTATUS_UPDATE, this, attributes); } /** @@ -2341,7 +2337,7 @@ void host::check_for_expired_acknowledgement() { SPDLOG_LOGGER_INFO(events_logger, "Acknowledgement of host '{}' just expired", name()); set_acknowledgement(AckType::NONE); - update_status(); + update_status(STATUS_ACKNOWLEDGEMENT); } } } @@ -2858,7 +2854,8 @@ void host::enable_flap_detection() { check_for_flapping(false, false, true); /* update host status */ - update_status(); + /* FIXME DBO: seems not necessary */ + // update_status(); } /* diff --git a/engine/src/logging/broker.cc b/engine/src/logging/broker.cc index 2bbd5a23d64..859b30aba8f 100644 --- a/engine/src/logging/broker.cc +++ b/engine/src/logging/broker.cc @@ -1,25 +1,24 @@ /** -* Copyright 2011-2021 Centreon -* -* This file is part of Centreon Engine. -* -* Centreon Engine is free software: you can redistribute it and/or -* modify it under the terms of the GNU General Public License version 2 -* as published by the Free Software Foundation. -* -* Centreon Engine is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with Centreon Engine. If not, see -* . -*/ + * Copyright 2011-2021 Centreon + * + * This file is part of Centreon Engine. + * + * Centreon Engine is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * Centreon Engine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Centreon Engine. If not, see + * . + */ #include "com/centreon/engine/broker.hh" #include "com/centreon/engine/logging/broker.hh" #include "com/centreon/engine/logging/logger.hh" -#include "com/centreon/exceptions/basic.hh" #include "com/centreon/unique_array_ptr.hh" using namespace com::centreon; diff --git a/engine/src/notifier.cc b/engine/src/notifier.cc index 50ba8b8b2f5..b99718d3528 100644 --- a/engine/src/notifier.cc +++ b/engine/src/notifier.cc @@ -16,7 +16,6 @@ * For more information : contact@centreon.com * */ -#include "com/centreon/engine/notifier.hh" #include "com/centreon/engine/broker.hh" #include "com/centreon/engine/checks/checker.hh" @@ -30,7 +29,6 @@ #include "com/centreon/engine/neberrors.hh" #include "com/centreon/engine/notification.hh" #include "com/centreon/engine/timezone_locker.hh" -#include "com/centreon/engine/utils.hh" using namespace com::centreon::engine; using namespace com::centreon::engine::logging; @@ -206,7 +204,7 @@ void notifier::set_last_problem_id(unsigned long last_problem_id) noexcept { } /** - * @brief Set the current notification number and update the notifier status. + * @brief Set the current notification number and send this update to Broker. * * @param num The notification number. */ @@ -218,7 +216,7 @@ void notifier::set_notification_number(int num) { _notification_number = num; /* update the status log with the notifier info */ - update_status(); + update_status(STATUS_NOTIFICATION_NUMBER); } bool notifier::_is_notification_viable_normal(reason_type type diff --git a/engine/src/service.cc b/engine/src/service.cc index ed514b431e2..4219833c22e 100644 --- a/engine/src/service.cc +++ b/engine/src/service.cc @@ -17,12 +17,10 @@ * */ -#include "com/centreon/engine/service.hh" #include #include "com/centreon/engine/broker.hh" -#include "com/centreon/engine/checkable.hh" #include "com/centreon/engine/checks/checker.hh" #include "com/centreon/engine/configuration/whitelist.hh" #include "com/centreon/engine/deleter/listmember.hh" @@ -31,18 +29,14 @@ #include "com/centreon/engine/exceptions/error.hh" #include "com/centreon/engine/flapping.hh" #include "com/centreon/engine/globals.hh" -#include "com/centreon/engine/hostdependency.hh" -#include "com/centreon/engine/logging.hh" #include "com/centreon/engine/logging/logger.hh" #include "com/centreon/engine/macros.hh" -#include "com/centreon/engine/macros/grab_host.hh" #include "com/centreon/engine/neberrors.hh" #include "com/centreon/engine/notification.hh" #include "com/centreon/engine/objects.hh" #include "com/centreon/engine/sehandlers.hh" #include "com/centreon/engine/string.hh" #include "com/centreon/engine/timezone_locker.hh" -#include "com/centreon/exceptions/interruption.hh" using namespace com::centreon; using namespace com::centreon::engine; @@ -849,7 +843,7 @@ void service::check_for_expired_acknowledgement() { // FIXME DBO: could be improved with something smaller. // We will see later, I don't know if there are many events concerning // acks. - update_status(); + update_status(STATUS_ACKNOWLEDGEMENT); } } } @@ -2827,8 +2821,7 @@ int service::run_async_check_local(int check_options, SPDLOG_LOGGER_DEBUG(checks_logger, "run id={} {} for service {} host {}", id, processed_cmd, _service_id, _hostname); - } catch (com::centreon::exceptions::interruption const& e) { - retry = true; + } catch (std::exception const& e) { run_failure("(Execute command failed)"); @@ -3171,10 +3164,13 @@ void service::disable_flap_detection() { } /** - * @brief Updates service status info. Send data to event broker. + * @brief Updates the status of the service partially. + * + * @param status_attributes A bits field based on status_attribute enum (default + * value: STATUS_ALL). */ -void service::update_status() { - broker_service_status(NEBTYPE_SERVICESTATUS_UPDATE, this); +void service::update_status(uint32_t status_attributes) { + broker_service_status(NEBTYPE_SERVICESTATUS_UPDATE, this, status_attributes); } /** diff --git a/engine/tests/commands/bin_connector_test_run.cc b/engine/tests/commands/bin_connector_test_run.cc index 3258433846b..3ef5498e37c 100644 --- a/engine/tests/commands/bin_connector_test_run.cc +++ b/engine/tests/commands/bin_connector_test_run.cc @@ -23,7 +23,7 @@ #include #include #include "com/centreon/engine/version.hh" -#include "com/centreon/exceptions/basic.hh" +#include "com/centreon/exceptions/msg_fmt.hh" #include "com/centreon/timestamp.hh" #define STATE_OK 0 @@ -31,8 +31,7 @@ #define STATE_CRITICAL 2 #define STATE_UNKNOWN 3 -// using namespace com::centreon; -// using namespace com::centreon::engine; +using com::centreon::exceptions::msg_fmt; /** * Simulate a execution process. @@ -119,17 +118,15 @@ static void query_execute(char const* q) { char* endptr(NULL); unsigned long command_id(strtol(startptr, &endptr, 10)); if (startptr == endptr) - throw basic_error() << "invalid query execute: " - "invalid command_id"; + throw msg_fmt("invalid query execute: invalid command_id"); startptr = endptr + 1; uint32_t timeout(strtol(startptr, &endptr, 10)); if (startptr == endptr) - throw basic_error() << "invalid query execute: " - "invalid is_executed"; + throw msg_fmt("invalid query execute: invalid is_executed"); startptr = endptr + 1; strtol(startptr, &endptr, 10); if (startptr == endptr) - throw basic_error() << "invalid query execute: invalid exit_code"; + throw msg_fmt("invalid query execute: invalid exit_code"); char const* cmd{endptr + 1}; std::vector cmdline = split(cmd); @@ -141,7 +138,7 @@ static void query_execute(char const* q) { std::string data(oss.str()); if (write(STDOUT_FILENO, data.c_str(), data.size()) != static_cast(data.size())) { - throw basic_error() << "write query execute failed"; + throw msg_fmt("write query execute failed"); } } @@ -163,7 +160,7 @@ static void query_quit(char const* q) { std::string data(oss.str()); if (write(STDOUT_FILENO, data.c_str(), data.size()) != static_cast(data.size())) - throw basic_error() << "write query quit failed"; + throw msg_fmt("write query quit failed"); exit(EXIT_SUCCESS); } @@ -186,7 +183,7 @@ static void query_version(char const* q) { std::string data(oss.str()); if (write(STDOUT_FILENO, data.c_str(), data.size()) != static_cast(data.size())) { - throw basic_error() << "write query version failed"; + throw msg_fmt("write query version failed"); std::ofstream outfile; outfile.open("/tmp/test.txt", std::ios_base::app); @@ -218,7 +215,7 @@ static int wait(std::string& query) { ssize_t ret(read(STDIN_FILENO, buffer, sizeof(buffer))); if (ret < 0) { char const* msg(strerror(errno)); - throw basic_error() << "invalid read: " << msg; + throw msg_fmt("invalid read: {}", msg); } if (!ret) return -1; @@ -237,7 +234,7 @@ static int wait(std::string& query) { uint32_t id(strtol(query_str, &endptr, 10)); if (query_str == endptr) { responses.pop_front(); - throw basic_error() << "invalid query"; + throw msg_fmt("invalid query"); } query.clear(); query.append(endptr + 1, response.size() - ((endptr + 1) - query_str)); @@ -271,7 +268,7 @@ int main() { static_cast(id) >= sizeof(tab_send_query) / sizeof(*tab_send_query) || !tab_send_query[id]) - throw basic_error() << "reveive bad request id: id=" << id; + throw msg_fmt("reveive bad request id: id={}", id); (*tab_send_query[id])(query.c_str()); } } catch (std::exception const& e) { diff --git a/gorgone/config/gorgoned-central-ssh.yml b/gorgone/config/gorgoned-central-ssh.yml index 144c3f47562..47409e07c25 100644 --- a/gorgone/config/gorgoned-central-ssh.yml +++ b/gorgone/config/gorgoned-central-ssh.yml @@ -43,7 +43,7 @@ configuration: - ^/usr/bin/php -q /usr/share/centreon/cron/centreon-helios\.php >> /var/log/centreon-helios\.log 2>&1\s*$ - ^centreon - ^mkdir - - ^/usr/share/centreon/www/modules/centreon-autodiscovery-server/script/run_save_discovered_host + - ^/usr/share/centreon/(www/modules/centreon-autodiscovery-server/script|bin)/run_save_discovered_host - ^/usr/share/centreon/bin/centreon -u \"centreon-gorgone\" -p \S+ -w -o CentreonWorker -a processQueue$ - name: proxy diff --git a/gorgone/config/gorgoned-central-zmq.yml b/gorgone/config/gorgoned-central-zmq.yml index a7a0c1d12e0..5a62b56b218 100644 --- a/gorgone/config/gorgoned-central-zmq.yml +++ b/gorgone/config/gorgoned-central-zmq.yml @@ -67,7 +67,7 @@ configuration: - ^/usr/bin/php -q /usr/share/centreon/cron/centreon-helios\.php >> /var/log/centreon-helios\.log 2>&1\s*$ - ^centreon - ^mkdir - - ^/usr/share/centreon/www/modules/centreon-autodiscovery-server/script/run_save_discovered_host + - ^/usr/share/centreon/(www/modules/centreon-autodiscovery-server/script|bin)/run_save_discovered_host - ^/usr/share/centreon/bin/centreon -u \"centreon-gorgone\" -p \S+ -w -o CentreonWorker -a processQueue$ - name: proxy diff --git a/gorgone/config/gorgoned-poller.yml b/gorgone/config/gorgoned-poller.yml index 735e864311d..1a68772230d 100644 --- a/gorgone/config/gorgoned-poller.yml +++ b/gorgone/config/gorgoned-poller.yml @@ -25,7 +25,7 @@ configuration: - ^/usr/bin/php -q /usr/share/centreon/cron/centreon-helios\.php >> /var/log/centreon-helios\.log 2>&1\s*$ - ^centreon - ^mkdir - - ^/usr/share/centreon/www/modules/centreon-autodiscovery-server/script/run_save_discovered_host + - ^/usr/share/centreon/(www/modules/centreon-autodiscovery-server/script|bin)/run_save_discovered_host - ^/usr/share/centreon/bin/centreon -u \"centreon-gorgone\" -p \S+ -w -o CentreonWorker -a processQueue$ - name: engine diff --git a/gorgone/config/gorgoned-remote-ssh.yml b/gorgone/config/gorgoned-remote-ssh.yml index fea645f45af..bbf31ac3594 100644 --- a/gorgone/config/gorgoned-remote-ssh.yml +++ b/gorgone/config/gorgoned-remote-ssh.yml @@ -30,7 +30,7 @@ configuration: - ^/usr/bin/php -q /usr/share/centreon/cron/centreon-helios\.php >> /var/log/centreon-helios\.log 2>&1\s*$ - ^centreon - ^mkdir - - ^/usr/share/centreon/www/modules/centreon-autodiscovery-server/script/run_save_discovered_host + - ^/usr/share/centreon/(www/modules/centreon-autodiscovery-server/script|bin)/run_save_discovered_host - ^/usr/share/centreon/bin/centreon -u \"centreon-gorgone\" -p \S+ -w -o CentreonWorker -a processQueue$ - name: proxy diff --git a/gorgone/config/gorgoned-remote-zmq.yml b/gorgone/config/gorgoned-remote-zmq.yml index 2eb9872d8f0..b9b00d9e2eb 100644 --- a/gorgone/config/gorgoned-remote-zmq.yml +++ b/gorgone/config/gorgoned-remote-zmq.yml @@ -35,7 +35,7 @@ configuration: - ^/usr/bin/php -q /usr/share/centreon/cron/centreon-helios\.php >> /var/log/centreon-helios\.log 2>&1\s*$ - ^centreon - ^mkdir - - ^/usr/share/centreon/www/modules/centreon-autodiscovery-server/script/run_save_discovered_host + - ^/usr/share/centreon/(www/modules/centreon-autodiscovery-server/script|bin)/run_save_discovered_host - ^/usr/share/centreon/bin/centreon -u \"centreon-gorgone\" -p \S+ -w -o CentreonWorker -a processQueue$ - name: proxy diff --git a/gorgone/contrib/gorgone_config_init.pl b/gorgone/contrib/gorgone_config_init.pl index b5702888331..94ddb133ad6 100644 --- a/gorgone/contrib/gorgone_config_init.pl +++ b/gorgone/contrib/gorgone_config_init.pl @@ -133,7 +133,7 @@ sub write_gorgone_config { - ^/usr/bin/php -q /usr/share/centreon/cron/centreon-helios\.php >> /var/log/centreon-helios\.log 2>&1\s*$ - ^centreon - ^mkdir - - ^/usr/share/centreon/www/modules/centreon-autodiscovery-server/script/run_save_discovered_host + - ^/usr/share/centreon/(www/modules/centreon-autodiscovery-server/script|bin)/run_save_discovered_host - ^/usr/share/centreon/bin/centreon -u \"centreon-gorgone\" -p \S+ -w -o CentreonWorker -a processQueue$ - name: proxy diff --git a/gorgone/contrib/named_pipe_reader.pl b/gorgone/contrib/named_pipe_reader.pl new file mode 100644 index 00000000000..16b2eb7b5c2 --- /dev/null +++ b/gorgone/contrib/named_pipe_reader.pl @@ -0,0 +1,68 @@ +#!/usr/bin/perl +# Copyright 2024 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +use strict; +use warnings; +use Getopt::Long; +use POSIX qw(mkfifo); +use DateTime; +use File::Basename; +use File::Path qw(make_path); +# global variable for easier verb() usage, don't need to pass the verbose argument. +my $args = {}; +sub main { + + GetOptions("pipename=s" => \$args->{pipename}, + "logfile=s" => \$args->{logfile}, # string + "verbose" => \$args->{verbose}) # flag + or die("Error in command line arguments\n"); + make_path(basename($args->{pipename})); + + verb("pipe to create is : " . $args->{pipename}); + unlink($args->{pipename}); + mkfifo($args->{pipename}, 0777) || die "can't mkfifo $args->{pipename} : $!"; + open(my $fh_log, '>>', $args->{logfile}) or die "can't open log file $args->{logfile} : $!"; + { + my $ofh = select $fh_log; + $| = 1; # work only on current filehandle, so we select our log fh and make it hot, and continue after. + select $ofh + } + while (1) { + open(my $fh_pipe, '<', $args->{pipename}) or die "can't open pipe $args->{pipename}"; + my $val = <$fh_pipe>; + verb("pipe gave value : " . $val); + my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time()); + my $date = sprintf( + '%04d-%02d-%02d %02d:%02d:%02d', + $year+1900, $mon+1, $mday, $hour, $min, $sec + ); + print $fh_log $date . " - " . $val; + + close $fh_pipe; + sleep(0.1); + } + +} +sub verb { + return if !$args->{verbose}; + print DateTime->now() . " - "; + print shift ; + print "\n"; +} +main; diff --git a/gorgone/docs/api/gorgone-openapi.yaml b/gorgone/docs/api/gorgone-openapi.yaml index a7e6a203ce5..7b5a5222002 100644 --- a/gorgone/docs/api/gorgone-openapi.yaml +++ b/gorgone/docs/api/gorgone-openapi.yaml @@ -1035,7 +1035,7 @@ components: command_line: type: string description: "Command line to execute" - example: "/usr/share/centreon/www/modules/centreon-autodiscovery-server/script/run_save_discovered_host --job-id=14" + example: "/usr/share/centreon/bin/run_save_discovered_host --job-id=14" required: - job_id - target diff --git a/gorgone/docs/api/index.html b/gorgone/docs/api/index.html index e2f378ac27d..9bc604ca4fa 100644 --- a/gorgone/docs/api/index.html +++ b/gorgone/docs/api/index.html @@ -477,7 +477,7 @@
403

Forbidden

post/centreon/autodiscovery/hosts

Local Gorgone instance

{protocol}://{server}:{port}/api/centreon/autodiscovery/hosts

Remote Gorgone instance

-
{protocol}://{server}:{port}/api/nodes/{id}/centreon/autodiscovery/hosts

Request samples

Content type
application/json
Copy
Expand all Collapse all
{
  • "job_id": 14,
  • "target": 2,
  • "command_line": "perl /usr/lib/centreon/plugins/centreon_generic_snmp.pl --plugin=os::linux::local::plugin --mode=discovery-snmp --subnet='10.1.2.3/24' --snmp-port='161' --snmp-version='2c' --snmp-community='public'",
  • "timeout": 300,
  • "execution":
    {
    },
  • "post_execution":
    {
    }
}

Response samples

Content type
application/json
Example
Copy
Expand all Collapse all
{
  • "token": "1d48a26a0fc37c1d8658222378044007d9c12311ba49b214de633739be05353415eee946f41b43babb6cb2a083a45c0d6359f361874af39a45b07542de8e2165"
}

Launch a host discovery job

Launch a host discovery job identified by id (even if in cron mode).

+
{protocol}://{server}:{port}/api/nodes/{id}/centreon/autodiscovery/hosts

Request samples

Content type
application/json
Copy
Expand all Collapse all
{
  • "job_id": 14,
  • "target": 2,
  • "command_line": "perl /usr/lib/centreon/plugins/centreon_generic_snmp.pl --plugin=os::linux::local::plugin --mode=discovery-snmp --subnet='10.1.2.3/24' --snmp-port='161' --snmp-version='2c' --snmp-community='public'",
  • "timeout": 300,
  • "execution":
    {
    },
  • "post_execution":
    {
    }
}

Response samples

Content type
application/json
Example
Copy
Expand all Collapse all
{
  • "token": "1d48a26a0fc37c1d8658222378044007d9c12311ba49b214de633739be05353415eee946f41b43babb6cb2a083a45c0d6359f361874af39a45b07542de8e2165"
}

Launch a host discovery job

Launch a host discovery job identified by id (even if in cron mode).

Authorizations:
path Parameters
job_id
required
integer
Example: 2

ID of the job

Responses

200

OK

401

Unauthorized

@@ -493,7 +493,7 @@
{protocol}://{server}:{port}/api/centreon/autodiscovery/hosts/{token}

Remote Gorgone instance

{protocol}://{server}:{port}/api/nodes/{id}/centreon/autodiscovery/hosts/{token}

Response samples

Content type
application/json
Example
Copy
Expand all Collapse all
{
  • "token": "1d48a26a0fc37c1d8658222378044007d9c12311ba49b214de633739be05353415eee946f41b43babb6cb2a083a45c0d6359f361874af39a45b07542de8e2165"
}