diff --git a/.github/scripts/windows-agent-compile.ps1 b/.github/scripts/windows-agent-compile.ps1 index 5326996f56..ed44fd015c 100644 --- a/.github/scripts/windows-agent-compile.ps1 +++ b/.github/scripts/windows-agent-compile.ps1 @@ -72,7 +72,8 @@ else { 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 and installer ---------------" cmake --build build_windows --config Release diff --git a/.github/workflows/windows-agent.yml b/.github/workflows/windows-agent.yml index 3c7f22eba4..933c8e7aff 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/** @@ -61,27 +68,15 @@ 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: Save agent package in cache - uses: actions/cache/save@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 - with: - path: centreon-monitoring-agent.zip - key: ${{ github.run_id }}-${{ github.sha }}-CMA-${{ github.head_ref || github.ref_name }} - enableCrossOsArchive: ${{ true }} - - name: Upload package artifacts if: | - github.event_name != 'workflow_dispatch' && + inputs.installer_in_artifact == true || + (github.event_name != 'workflow_dispatch' && contains(fromJson('["stable"]'), needs.get-version.outputs.stability) && ! cancelled() && ! contains(needs.*.result, 'failure') && - ! contains(needs.*.result, 'cancelled') + ! 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 + path: agent\installer\centreon-monitoring-agent.exe diff --git a/agent/CMakeLists.txt b/agent/CMakeLists.txt index 510a237da9..fc9a0138a6 100644 --- a/agent/CMakeLists.txt +++ b/agent/CMakeLists.txt @@ -98,6 +98,7 @@ add_custom_command( WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + set( SRC_COMMON ${SRC_DIR}/agent.grpc.pb.cc ${SRC_DIR}/agent.pb.cc @@ -122,6 +123,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") @@ -165,7 +169,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 +181,9 @@ else() absl::any absl::log absl::base absl::bits Boost::program_options fmt::fmt) + + add_subdirectory(installer) + endif() diff --git a/agent/installer/CMakeLists.txt b/agent/installer/CMakeLists.txt new file mode 100644 index 0000000000..7f9cd76943 --- /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 0000000000..b5197820b8 --- /dev/null +++ b/agent/installer/centreon-monitoring-agent-modify.nsi @@ -0,0 +1,123 @@ +# +# 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}" + +!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" + +Name "Centreon Monitoring Agent ${VERSIONMAJOR}.${VERSIONMINOR}.${VERSIONBUILD}" +Icon "resources/logo_centreon.ico" +RequestExecutionLevel admin +AllowRootDirInstall true + + + +!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 .onInit + setShellVarContext all + !insertmacro VerifyUserIsAdmin +functionEnd + +/** + * @brief at the end of the installer, we stop and start cma +*/ +Function encryption_next_and_restart_centagent + Call encryption_dlg_onNext + + !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 + + !insertmacro SERVICE "start" "${SERVICE_NAME}" "" + 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 0000000000..dadc0823c9 --- /dev/null +++ b/agent/installer/centreon-monitoring-agent.nsi @@ -0,0 +1,285 @@ +# +# 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}" +!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" + +Name "Centreon Monitoring Agent ${VERSIONMAJOR}.${VERSIONMINOR}.${VERSIONBUILD}" +Icon "resources/logo_centreon.ico" +LicenseData "resources/license.txt" +RequestExecutionLevel admin +AllowRootDirInstall true + +InstallDir "$PROGRAMFILES64\${COMPANYNAME}\${APPNAME}" +!define PLUGINS_DIR "$PROGRAMFILES64\${COMPANYNAME}\Plugins" + +!define HELPURL "https://www.centreon.com/" + +Var plugins_url + + + +!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 .onInit + setShellVarContext all + !insertmacro VerifyUserIsAdmin +functionEnd + + +/** + * @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" + 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" +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" + +SectionEnd + +/** + * @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" + 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 + + !insertmacro VerifyUserIsAdmin + + MessageBox MB_YESNO "Do you want to remove the Centreon plugins for the agents?" IDNO no_plugins_remove + rmDir ${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: + +functionEnd \ No newline at end of file diff --git a/agent/installer/dlg_helper.nsi b/agent/installer/dlg_helper.nsi new file mode 100644 index 0000000000..c3953ab424 --- /dev/null +++ b/agent/installer/dlg_helper.nsi @@ -0,0 +1,452 @@ +# +# 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 + +#Match to windows file path C:\tutu yoyo1234 titi\fgdfgdg.rt +!define FILE_PATH_REGEXP '^[a-zA-Z]:([\\|\/](([\w\.]+\s+)*[\w\.]+)+)+$' + +/*************************************************************************************** + 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" $0 + ${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 0000000000..4719049d18 --- /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 0000000000..77b1b5ea00 --- /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 0000000000..6ac8d81815 --- /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 0000000000..afd10fb8eb --- /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 0000000000..2b2006d4f7 --- /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 0000000000..a5e149adb7 --- /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 0000000000..6138b2a5b6 --- /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 0000000000..3e02d12f70 --- /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 0000000000..5d878606ce --- /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 0000000000..d6541123b8 --- /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 0000000000..d7fc835a64 --- /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 0000000000..088a223f56 --- /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 0000000000..5aa0757a7a --- /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 0000000000..963d5f47f2 --- /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 0000000000..ac84523762 --- /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 0000000000..ef3ff2a92b --- /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 0000000000..234a48dbf7 --- /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 0000000000..b8725d2161 --- /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 0000000000..e33b0d8ed1 --- /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 0000000000..72d9128759 --- /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 0000000000..1d3373bc6b --- /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 0000000000..79b6773608 --- /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 0000000000..f6a8949641 --- /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 0000000000..2fde0a9285 --- /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 0000000000..07ab4fbf28 --- /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 0000000000..046d605337 --- /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 0000000000..582f265347 --- /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 0000000000..7bb2bf526d --- /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 0000000000..925080df34 --- /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 0000000000..64c952ab2f --- /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 0000000000..afe455283f --- /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 0000000000..5a489ba35e --- /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 0000000000..f5ed4435ab --- /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 0000000000..c09a7706f9 --- /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 0000000000..2427cfd442 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 0000000000..d01dc48a6b 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 0000000000..d867f8c2e8 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 0000000000..f34c717db4 --- /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 0000000000..acdf9435a0 --- /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 0000000000..591001a938 --- /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 0000000000..b8607e850d --- /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 0000000000..d740e88600 --- /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 0000000000..4bfc5580c1 --- /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 0000000000..86fbd3f2a7 --- /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 0000000000..e0174d6b34 --- /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 0000000000..78473c060c --- /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 0000000000..799bd42c84 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 0000000000..78473c060c --- /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 0000000000..b3bfe1d05c 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 0000000000..fb4d346e2d --- /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 0000000000..b050296f85 --- /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 0000000000..09c26e9b07 --- /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 0000000000..f077c2c639 --- /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 0000000000..b8b78842f7 --- /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 0000000000..58352480a4 --- /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 0000000000..49339dfafe --- /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 0000000000..058d46e6bf 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 0000000000..6992f3fe25 --- /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 0000000000..77527006ad --- /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 0000000000..42c994ea14 --- /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 0000000000..3e02d12f70 --- /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 0000000000..5d878606ce --- /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 0000000000..d6541123b8 --- /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 0000000000..97a43f859b 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 0000000000..5c66254164 --- /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 0000000000..b5a78faa3b 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 0000000000..5dd03cdeb3 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 0000000000..09cee51f94 --- /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 0000000000..7267bb6d54 --- /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 0000000000..b0e7623cec --- /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 0000000000..ada981cac7 --- /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 0000000000..282e559415 --- /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 0000000000..9b465ef225 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 0000000000..c2a2ad34d1 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 0000000000..023c0dbcaa 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 0000000000..66cb100521 --- /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 0000000000..bae9fc920b --- /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 0000000000..8cd8e5d88a --- /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 0000000000..31879b7b71 --- /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 0000000000..e9017f604c --- /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 0000000000..e48e8484ef --- /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 0000000000..4e6b50c0a1 --- /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 Espaol" + }, { + "event_types": [ "start", "end", "error" ], + "gender": "female", + "lang": "fr-FR", + "remote": true, + "voice_name": "Google Franais" + }, { + "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 0000000000..68a82d0c55 --- /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 0000000000..4ae692d8b7 --- /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 0000000000..0f2f0591e4 --- /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 0000000000..e231b277c8 --- /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 0000000000..96d91388bb --- /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 0000000000..6f0c48d2f6 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 0000000000..c11ede1f13 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 0000000000..c7999466b2 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 0000000000..1dfbcbfb06 --- /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 0000000000..e787aba566 --- /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 0000000000..6bcfada414 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 0000000000..cc87299f84 --- /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 0000000000..c15d1f35d6 --- /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 0000000000..f1e7fb2211 --- /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 0000000000..0d520a3215 --- /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 0000000000..fb7cba0ce3 --- /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 0000000000..4d7480e8bc --- /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 0000000000..482b8a18ea --- /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 0000000000..130a461317 --- /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 0000000000..c4a55c45b4 --- /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 0000000000..6a56fbe519 --- /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 0000000000..6cc06dbea2 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 0000000000..84e6db45bf --- /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 0000000000..164ab301ed --- /dev/null +++ b/agent/installer/resources/log_dlg.nsddef @@ -0,0 +1,39 @@ + + + + Call init_log_dlg +Call on_log_type_changed + + + + + + + EventLog + 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 0000000000..30ede3e8d2 --- /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 "EventLog" + ${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 0000000000..8e032cde7c 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 0000000000..e64ac5cb85 --- /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 0000000000..6af81ff7ce --- /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 Centron:" + 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/version.nsi.in b/agent/installer/version.nsi.in new file mode 100644 index 0000000000..7ccd0fc052 --- /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/src/agent.rc.in b/agent/src/agent.rc.in new file mode 100644 index 0000000000..86739dae06 --- /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 05ba6276b1..e551c5164f 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); +}