;NSIS Modern User Interface
;Multilingual Cloud Installer Script
;Written by Cs�k Tam�s

;--------------------------------
;Include Modules
!include "MUI2.nsh"
!include "LogicLib.nsh"
!include "FileFunc.nsh"
!include "x64.nsh"

;--------------------------------
;Defining new constants
  !define Company "CIRCLE Cloud"
  !define AppName "Client"
  !define AppUrlName "BME CIRCLE"
  !define AppUrl "http://cloud.bme.hu/"
  !define AppUninstaller "Uninstall.exe"
  !define IconName "cloud"
  !define Show_output "True"
  !define DefaulLocation "$LOCALAPPDATA\CIRCLE"
  !define LowestSupportedPythonVersion "6"
  !define HighestSupportedPythonVersion "7"
  !define LogInformationTime 2000
  
  ;String manipulations
  !define Explode "!insertmacro Explode"
  !define StrCase "!insertmacro StrCase"
  !define StrTrimNewLines "!insertmacro StrTrimNewLines"
;--------------------------------
;General
  !macro Explode Length Separator String
    Push    '${Separator}'
    Push    '${String}'
    Call    Explode
    Pop     '${Length}'
  !macroend
  !macro StrCase ResultVar String Case
    Push "${String}"
    Push "${Case}"
    Call StrCase
    Pop "${ResultVar}"
  !macroend
  !macro StrTrimNewLines ResultVar String
    Push "${String}"
    Call StrTrimNewLines
    Pop "${ResultVar}"
  !macroend
  ;Properly display all languages (Installer will not work on Windows 95, 98 or ME!)
  Unicode true
  
  ;Name and file
  Name "${Company} ${AppName}"
  OutFile "..\..\dist\CIRCLE_Client_Setup.exe"
  
  ;Disable to skip files from installing
  AllowSkipFiles off
  
  ;If there are existing files stored try to overwrite it
  SetOverwrite try
  
  ;Default installation folder
  InstallDir "${DefaulLocation}"
  
  ;Get installation folder from registry if available
  InstallDirRegKey HKCU "Software\${Company} ${AppName}" "install_directory"
  
  ;Request application privileges
  RequestExecutionLevel admin
    
      
;--------------------------------
;Interface Settings
  !define MUI_ABORTWARNING
  
  !define MUI_ICON "${IconName}.ico"

  !define MUI_UNICON "${IconName}.ico"
  
  ;Show all languages, despite user's codepage
  !define MUI_LANGDLL_ALLLANGUAGES

;--------------------------------
;Language Selection Dialog Settings
;Remember the installer language
  !define MUI_LANGDLL_REGISTRY_ROOT "HKCU" 
  !define MUI_LANGDLL_REGISTRY_KEY "Software\${Company} ${AppName}" 
  !define MUI_LANGDLL_REGISTRY_VALUENAME "Installer Language"
  
;--------------------------------
;Pages
  !insertmacro MUI_PAGE_LICENSE "gpl-3.0.txt"
  !insertmacro MUI_PAGE_COMPONENTS
  !insertmacro MUI_PAGE_DIRECTORY
  !insertmacro MUI_PAGE_INSTFILES
  ;Done fuction to launch install.bat
  !define MUI_PAGE_CUSTOMFUNCTION_PRE Done
  !insertmacro MUI_PAGE_FINISH
  
  !insertmacro MUI_UNPAGE_CONFIRM
  !insertmacro MUI_UNPAGE_INSTFILES
  
;--------------------------------
;Languages
  !insertmacro MUI_LANGUAGE "English" ;first language is the default language
  !insertmacro MUI_LANGUAGE "Hungarian"

;--------------------------------
;Reserve Files
  !insertmacro MUI_RESERVEFILE_LANGDLL

;--------------------------------
;Language strings
  ;SectionGroup names
  LangString NAME_Install ${LANG_ENGLISH} "Components"
  LangString NAME_Install ${LANG_HUNGARIAN} "Komponensek"
  
  LangString NAME_Functions ${LANG_ENGLISH} "Functions"
  LangString NAME_Functions ${LANG_HUNGARIAN} "Funkci�k"

  ;CIRCLE Client (SecInstall)
    ;NAME
  LangString NAME_SecInstall ${LANG_ENGLISH} "CIRCLE Client"
  LangString NAME_SecInstall ${LANG_HUNGARIAN} "CIRCLE Kliens"
  
    ;DESC
  LangString DESC_SecInstall ${LANG_ENGLISH} "Install the core of the CIRCLE Client.$\r$\n\
  Used for [RDP / SSH] type of connections.$\r$\n\
  Automates all installed, third party connection tools."
  LangString DESC_SecInstall ${LANG_HUNGARIAN} "A CIRCLE Kliens alapj�nak telep�t�se.$\r$\n\
  [RDP / SSH] f�le kapcsolatokhoz haszn�lt.$\r$\n\
  Automatiz�lja az install�lt, harmadik f�lt�l sz�rmaz� szoftverek haszn�lat�t."
  ;Python search (PythonLookup)
    ;NAME
  LangString NAME_PythonLookup ${LANG_ENGLISH} "Search Python"
  LangString NAME_PythonLookup ${LANG_HUNGARIAN} "Python keres�s"
    
    ;DESC
  LangString DESC_PythonLookup ${LANG_ENGLISH} "Use ONLY if necessary!$\r$\n\
  Search the filesystem for Python installation. Usefull when Python was installed without accessing registry before.$\r$\n\
  Installation will take more time."
  LangString DESC_PythonLookup ${LANG_HUNGARIAN} "Csak sz�ks�g eset�n!$\r$\n\
  A f�jlrendszer keres�se Python ut�n. Hasznos, ha a Python-t Registry n�lk�li opci�val lett telep�tve kor�bban.$\r$\n\
  A telep�t�st jelent�sen lelass�tja."
  
    ;STATUS
  LangString STATUS_PythonSearch ${LANG_ENGLISH} "Searching for Python. This could take some time. Looking at drive:"
  LangString STATUS_PythonSearch ${LANG_HUNGARIAN} "Python keres�se a f�jlrendszerben. Ez eltarthat egy darabig. Keres�s alapja:"
  
  LangString STATUS_PythonFound ${LANG_ENGLISH} "Python found at "
  LangString STATUS_PythonFound ${LANG_HUNGARIAN} "Python megtal�lva az al�bbi k�nyvt�rban: "
  
  LangString STATUS_PythonVersionSearch ${LANG_ENGLISH} "Determining Python version."
  LangString STATUS_PythonVersionSearch ${LANG_HUNGARIAN} "Telep�tett Python verzi� kider�t�se."
  
  LangString STATUS_PythonVersionFound ${LANG_ENGLISH} "Installed Python version is:"
  LangString STATUS_PythonVersionFound ${LANG_HUNGARIAN} "A telep�tett Python verzi�ja:"
  
  LangString STATUS_PythonArchitectSearch ${LANG_ENGLISH} "Deteremining installed Python mode (32bit or 64bit)."
  LangString STATUS_PythonArchitectSearch ${LANG_HUNGARIAN} "Install�lt Python futtat�si m�dj�nak kider�t�se (32bit vagy 64bit)."
  
  LangString STATUS_PythonArchitectFound ${LANG_ENGLISH} "Installed Python mode is:"
  LangString STATUS_PythonArchitectFound ${LANG_HUNGARIAN} "A telep�tett Python m�dja:"
  
  LangString STATUS_PythonNotSupported ${LANG_ENGLISH} "The installed Python version is not supported!$\r$\n\
  To procede please uninstall Python first." 
  LangString STATUS_PythonNotSupported ${LANG_HUNGARIAN} "A feltelep�tett Python verzi�ja nem t�mogatott!$\r$\n\
  A sikeres telep�t�shez el kell el�bb t�vol�tania a Python-t."
  
  LangString STATUS_PythonNotFound ${LANG_ENGLISH} "Python not found in the filesystem!"
  LangString STATUS_PythonNotFound ${LANG_HUNGARIAN}} "Nem tal�lhat� Python a f�jlrendszerben!"

  LangString STATUS_PythonArchitectNotFound ${LANG_ENGLISH} "Could NOT determine the installed Python mode!$\r$\n\
  To procede please uninstall Python first."
  LangString STATUS_PythonArchitectNotFound ${LANG_HUNGARIAN} "Nem siker�lt kider�teni a feltelep�tett Python m�dj�t!$\r$\n\
  A sikeres telep�t�shez el kell el�bb t�vol�tania a Python-t."
  
  ;NX Client (NXClient)
    ;NAME
  LangString NAME_NXClient ${LANG_ENGLISH} "NX Client"
  LangString NAME_NXClient ${LANG_HUNGARIAN} "NX Kliens"
    
    ;DESC
  LangString DESC_NXClient ${LANG_ENGLISH} "Check whether you want to install a CIRCLE compatible NX Client by NoMachine.$\r$\n\
  Used for [NX] type of connections."
  LangString DESC_NXClient ${LANG_HUNGARIAN} "V�lassza ki, ha fel szeretn� telep�teni a NoMachine �ltal gy�rtott NX Klienst.$\r$\n\
  [NX] f�le kapcsolatokhoz haszn�lt."
  
  ;Setup
  LangString STATUS_ExecutingScript ${LANG_ENGLISH} "Executing setup script. Log files can be found at:"
  LangString STATUS_ExecutingScript ${LANG_HUNGARIAN} "Install�ci�s script futtat�sa. A folyamat napl�ja:"
;--------------------------------
;Global variables
  Var /GLOBAL python_location
  Var /GLOBAL python_version
  Var /GLOBAL python_architect
  Var /GLOBAL found_python
  Var /GLOBAL nx_install
  Var /GLOBAL append
;--------------------------------
;Installer Sections
SectionGroup /e '!$(NAME_Install)'
    Section $(NAME_SecInstall) SecInstall
      SectionIn RO
      SetOutPath "$INSTDIR"
      
      ;ADD OWN FILES HERE----------------------------------------
      File /r /x *nxclient-3.5.0-9.exe /x *nx_client_installer.py installer
      File /r uninstaller

      ;Store installation folder
      WriteRegStr HKCU "Software\${Company} ${AppName}" "install_directory" $INSTDIR
      
      ;Create uninstaller
      WriteUninstaller "$INSTDIR\${AppUninstaller}"
      
      ;Creating ShortCuts
      CreateDirectory '$SMPROGRAMS\${Company}\${AppName}'
      StrCmp $LANGUAGE ${LANG_HUNGARIAN} 0 +3
        WriteINIStr "$SMPROGRAMS\${Company}\L�togasd meg a ${AppUrlName}-t.url" "InternetShortcut" "URL" "${AppUrl}"
        Goto +2
      WriteINIStr "$SMPROGRAMS\${Company}\Visit the ${AppUrlName}.url" "InternetShortcut" "URL" "${AppUrl}"
      CreateShortCut '$SMPROGRAMS\${Company}\${AppName}\Uninstall ${AppName}.lnk' '$INSTDIR\${AppUninstaller}' "" '$INSTDIR\${AppUninstaller}' 0

    SectionEnd
    Section /o $(NAME_NXClient) NXClient
        SetOutPath "$INSTDIR\installer"
        File 'installer\nxclient-3.5.0-9.exe'
        File 'installer\nx_client_installer.py'
    SectionEnd
SectionGroupEnd
SectionGroup /e $(NAME_Functions)
    Section /o $(NAME_PythonLookup) PythonLookup
        StrCpy $found_python "false"
        ${GetDrives} "HDD" "PythonSearch"
        StrCmp $found_python "true" appendExec
        Goto LookupEnd
        appendExec:
           StrCpy $append ' $python_architect $python_version "$python_location\"'
        LookupEnd:
    SectionEnd
SectionGroupEnd

;--------------------------------
;Installer Functions
Function .onInit
  ${If} ${RunningX64}
        ${DisableX64FSRedirection}
        SetRegView 64
  ${EndIf}
  !insertmacro MUI_LANGDLL_DISPLAY
FunctionEnd
Function PythonSearch
    StrCpy $python_location ""
    DetailPrint '$(STATUS_PythonSearch) "$9"'
    Push "easy_install.exe" ;File or folder to search. Wildcards are supported.
    Push $9 ;Path where to search for the file or folder.
    Push $0
    GetFunctionAddress $0 "CallbackFunction" ;Custom callback function name
    Exch $0
    Push "1" ;Include subfolders in search. (0 = false, 1 = true)
    Push "0" ;Enter subfolders with ".". This only works if "Include subfolders in search" is set to 1 (true). (0 = false, 1 = true)
    Call SearchFile
    StrCmp $python_location "" PythonNotFound 
    Var /GLOBAL explodeChar
    StrCpy $explodeChar ' '
    DetailPrint $(STATUS_PythonVersionSearch)
    nsExec::ExecToStack '"$python_location\python.exe" -V'
    Pop $0
    ${If} $0 = 0
        Pop $0
        ${StrTrimNewLines} $python_version $0
        loop:
        ${Explode} $0 $explodeChar $python_version
        ${For} $1 1 $0
            Pop $2
            StrCmp $explodeChar ' ' CutPython
            StrCmp $1 "2" secondNumber
                StrCmp $2 "2" versionCount
                    wrongVersion:
                    MessageBox MB_OK $(STATUS_PythonNotSupported)
                    Abort $(STATUS_PythonNotSupported)
                    Goto PythonFin
                versionCount:
                    StrCpy $4 $2
                    Goto loopNext
            secondNumber:
                ${If} $2 S>= ${LowestSupportedPythonVersion}
                    ${If} $2 S<= ${HighestSupportedPythonVersion}
                        StrCpy $python_version "$4$explodeChar$2"
                        DetailPrint '$(STATUS_PythonVersionFound) $python_version'
                        StrCpy $found_python "true"
                        Goto PythonMode
                    ${Else}
                        Goto wrongVersion
                    ${EndIf}
                ${Else}
                    Goto wrongVersion
                ${EndIf}
            Goto loopNext
            CutPython:
                ${StrCase} $3 $2 "U"
                StrCmp $3 "PYTHON" loopNext
                    StrCpy $python_version $2
                    StrCpy $explodeChar '.'
                    Goto loop
            loopNext:
        ${Next}
    ${Else}
        PythonNotFound:
        MessageBox MB_OK $(STATUS_PythonNotFound)
        DetailPrint $(STATUS_PythonNotFound)
        Goto PythonFin
    ${EndIf}
    
    PythonMode:
        DetailPrint $(STATUS_PythonArchitectSearch)
        nsExec::ExecToStack '"$python_location\python.exe" -c $\"import struct;print( 8 * struct.calcsize($\'P$\'))$\"'
        Pop $0
        ${If} $0 = 0
            Pop $0
            ${StrTrimNewLines} $python_architect $0
            DetailPrint '$(STATUS_PythonArchitectFound) $python_architectbit'
        ${Else}
            StrCpy $found_python "false"
            MessageBox MB_OK $(STATUS_PythonArchitectNotFound)
            DetailPrint $(STATUS_PythonArchitectNotFound)
        ${EndIf}
        StrCpy $6 StopGetDrives
    PythonFin:
    Push $6
FunctionEnd
Function Done
  SectionGetFlags ${NXClient} $9
  IntOp $9 $9 & ${SF_SELECTED} 
  IntCmp $9 ${SF_SELECTED} equal
  StrCpy $nx_install "False"
  Goto done
  equal:
    StrCpy $nx_install "True"
  done:
  DetailPrint '$(STATUS_ExecutingScript) $INSTDIR\install(_error).log'
  Sleep ${LogInformationTime}
  ExecWait '"$INSTDIR\installer\install.cmd" "$INSTDIR" ${Show_output} $nx_install "${AppUrl}" $append >"$INSTDIR\install.log" 2>"$INSTDIR\install_error.log"'
  RMDir /r "$INSTDIR\installer"
FunctionEnd
Function CallbackFunction
  ${GetParent} $R0 $python_location
  DetailPrint '$(STATUS_PythonFound) "$python_location\"'
  Push "Stop"
FunctionEnd
Function SearchFile
 
  Exch 4
  Exch
  Exch 3
  Exch $R0 ; directory in which to search
  Exch 4
  Exch
  Exch $R1 ; file or folder name to search in
  Exch 3
  Exch 2
  Exch $R2
  Exch 2
  Exch $R3
  Exch
  Push $R4
  Exch
  Push $R5
  Exch
  Push $R6
  Exch
  Exch $R7 ;search folders with "."
 
  StrCpy $R5 $R2 ;$R5 = custom function name
  StrCpy $R6 $R3 ;$R6 = include subfolders
 
  StrCpy $R2 ""
  StrCpy $R3 ""
 
  # Remove \ from end (if any) from the file name or folder name to search
  StrCpy $R2 $R1 1 -1
  StrCmp $R2 \ 0 +2
  StrCpy $R1 $R1 -1
 
  # Detect if the search path have backslash to add the backslash
  StrCpy $R2 $R0 1 -1
  StrCmp $R2 \ +2
  StrCpy $R0 "$R0\"
 
  # File (or Folder) Search
  ##############
 
  # Get first file or folder name
 
  FindFirst $R2 $R3 "$R0$R1"
 
  FindNextFile:
 
  # This loop, search for files or folders with the same conditions.
 
    StrCmp $R3 "" NoFiles
      StrCpy $R4 "$R0$R3"
 
  # Preparing variables for the Callback function
 
    Push $R7
    Push $R6
    Push $R5
    Push $R4
    Push $R3
    Push $R2
    Push $R1
    Push $R0
 
  # Call the Callback function
 
    Call $R5
 
  # Returning variables
 
    Push $R8
    Exch
    Pop $R8
 
    Exch
    Pop $R0
    Exch
    Pop $R1
    Exch
    Pop $R2
    Exch
    Pop $R3
    Exch
    Pop $R4
    Exch
    Pop $R5
    Exch
    Pop $R6
    Exch
    Pop $R7
 
    StrCmp $R8 "Stop" 0 +3
      Pop $R8
      Goto Done
 
    Pop $R8
 
  # Detect if have another file
 
    FindNext $R2 $R3
      Goto FindNextFile ;and loop!
 
  # If don't have any more files or folders with the condictions
 
  NoFiles:
 
  FindClose $R2
 
  # Search in Subfolders
  #############
 
  # If you don't want to search in subfolders...
 
  StrCmp $R6 0 NoSubfolders 0
 
  # SEARCH FOLDERS WITH DOT
 
  # Find the first folder with dot
 
  StrCmp $R7 1 0 EndWithDot
 
    FindFirst $R2 $R3 "$R0*.*"
    StrCmp $R3 "" NoSubfolders
      StrCmp $R3 "." FindNextSubfolderWithDot 0
        StrCmp $R3 ".." FindNextSubfolderWithDot 0
          IfFileExists "$R0$R3\*.*" RecallingOfFunction 0
 
  # Now, detect the next folder with dot
 
      FindNextSubfolderWithDot:
 
      FindNext $R2 $R3
      StrCmp $R3 "" NoSubfolders
        StrCmp $R3 "." FindNextSubfolder 0
          StrCmp $R3 ".." FindNextSubfolder 0
            IfFileExists "$R0$R3\*.*" RecallingOfFunction FindNextSubfolderWithDot
 
  EndWithDot:
 
  # SEARCH FOLDERS WITHOUT DOT
 
  # Skip ., and .. (C:\ don't have .., so have to detect if is :\)
 
  FindFirst $R2 $R3 "$R0*."
 
  Push $R6
 
  StrCpy $R6 $R0 "" 1
  StrCmp $R6 ":\" +2
 
  FindNext $R2 $R3
 
  Pop $R6
 
  # Now detect the "really" subfolders, and loop
 
  FindNextSubfolder:
 
  FindNext $R2 $R3
  StrCmp $R3 "" NoSubfolders
    IfFileExists "$R0$R3\" FindNextSubfolder
 
  # Now Recall the function (making a LOOP)!
 
  RecallingOfFunction:
 
  Push $R1
  Push "$R0$R3\"
  Push "$R5"
  Push "$R6"
  Push "$R7"
    Call SearchFile
 
  # Now, find the next Subfolder
 
    Goto FindNextSubfolder
 
  # If don't exist more subfolders...
 
  NoSubfolders:
 
  FindClose $R2
 
  # Returning Values to User
 
  Done:
 
  Pop $R7
  Pop $R6
  Pop $R5
  Pop $R4
  Pop $R3
  Pop $R2
  Pop $R1
  Pop $R0
 
FunctionEnd
Function Explode
  ; Initialize variables
  Var /GLOBAL explString
  Var /GLOBAL explSeparator
  Var /GLOBAL explStrLen
  Var /GLOBAL explSepLen
  Var /GLOBAL explOffset
  Var /GLOBAL explTmp
  Var /GLOBAL explTmp2
  Var /GLOBAL explTmp3
  Var /GLOBAL explArrCount
 
  ; Get input from user
  Pop $explString
  Pop $explSeparator
 
  ; Calculates initial values
  StrLen $explStrLen $explString
  StrLen $explSepLen $explSeparator
  StrCpy $explArrCount 1
 
  ${If}   $explStrLen <= 1          ;   If we got a single character
  ${OrIf} $explSepLen > $explStrLen ;   or separator is larger than the string,
    Push    $explString             ;   then we return initial string with no change
    Push    1                       ;   and set array's length to 1
    Return
  ${EndIf}
 
  ; Set offset to the last symbol of the string
  StrCpy $explOffset $explStrLen
  IntOp  $explOffset $explOffset - 1
 
  ; Clear temp string to exclude the possibility of appearance of occasional data
  StrCpy $explTmp   ""
  StrCpy $explTmp2  ""
  StrCpy $explTmp3  ""
 
  ; Loop until the offset becomes negative
  ${Do}
    ;   If offset becomes negative, it is time to leave the function
    ${IfThen} $explOffset == -1 ${|} ${ExitDo} ${|}
 
    ;   Remove everything before and after the searched part ("TempStr")
    StrCpy $explTmp $explString $explSepLen $explOffset
 
    ${If} $explTmp == $explSeparator
        ;   Calculating offset to start copy from
        IntOp   $explTmp2 $explOffset + $explSepLen ;   Offset equals to the current offset plus length of separator
        StrCpy  $explTmp3 $explString "" $explTmp2
 
        Push    $explTmp3                           ;   Throwing array item to the stack
        IntOp   $explArrCount $explArrCount + 1     ;   Increasing array's counter
 
        StrCpy  $explString $explString $explOffset 0   ;   Cutting all characters beginning with the separator entry
        StrLen  $explStrLen $explString
    ${EndIf}
 
    ${If} $explOffset = 0                       ;   If the beginning of the line met and there is no separator,
                                                ;   copying the rest of the string
        ${If} $explSeparator == ""              ;   Fix for the empty separator
            IntOp   $explArrCount   $explArrCount - 1
        ${Else}
            Push    $explString
        ${EndIf}
    ${EndIf}
 
    IntOp   $explOffset $explOffset - 1
  ${Loop}
 
  Push $explArrCount
FunctionEnd
Function StrCase
/*After this point:
  ------------------------------------------
  $0 = String (input)
  $1 = Case (input)
  $2 = StrLength (temp)
  $3 = StartChar (temp)
  $4 = EndChar (temp)
  $5 = ResultStr (temp)
  $6 = CurrentChar (temp)
  $7 = LastChar (temp)
  $8 = Temp (temp)*/
 
  ;Get input from user
  Exch $1
  Exch
  Exch $0
  Exch
  Push $2
  Push $3
  Push $4
  Push $5
  Push $6
  Push $7
  Push $8
 
  ;Initialize variables
  StrCpy $2 ""
  StrCpy $3 ""
  StrCpy $4 ""
  StrCpy $5 ""
  StrCpy $6 ""
  StrCpy $7 ""
  StrCpy $8 ""
 
  ;Upper and lower cases are simple to use
  ${If} $1 == "U"
 
    ;Upper Case:
    ;-----------
    ;Convert all characters to upper case.
 
    System::Call "User32::CharUpper(t r0 r5)i"
    Goto StrCase_End
  ${ElseIf} $1 == "L"
 
    ;Lower Case:
    ;-----------
    ;Convert all characters to lower case.
 
    System::Call "User32::CharLower(t r0 r5)i"
    Goto StrCase_End
  ${EndIf}
 
  ;For the rest of cases:
  ;Get "String" length
  StrLen $2 $0
 
  ;Make a loop until the end of "String"
  ${For} $3 0 $2
    ;Add 1 to "EndChar" counter also
    IntOp $4 $3 + 1
 
    # Step 1: Detect one character at a time
 
    ;Remove characters before "StartChar" except when
    ;"StartChar" is the first character of "String"
    ${If} $3 <> 0
      StrCpy $6 $0 `` $3
    ${EndIf}
 
    ;Remove characters after "EndChar" except when
    ;"EndChar" is the last character of "String"
    ${If} $4 <> $2
      ${If} $3 = 0
        StrCpy $6 $0 1
      ${Else}
        StrCpy $6 $6 1
      ${EndIf}
    ${EndIf}
 
    # Step 2: Convert to the advanced case user chose:
 
    ${If} $1 == "T"
 
      ;Title Case:
      ;------------------
      ; Convert all characters after a non-alphabetic character to upper case.
      ; Else convert to lower case.
 
      ;Use "IsCharAlpha" for the job
      System::Call "*(&t1 r7) i .r8"
      System::Call "*$8(&i1 .r7)"
      System::Free $8
      System::Call "user32::IsCharAlpha(i r7) i .r8"
 
      ;Verify "IsCharAlpha" result and convert the character
      ${If} $8 = 0
        System::Call "User32::CharUpper(t r6 r6)i"
      ${Else}
        System::Call "User32::CharLower(t r6 r6)i"
      ${EndIf}
    ${ElseIf} $1 == "S"
 
      ;Sentence Case:
      ;------------------
      ; Convert all characters after a ".", "!" or "?" character to upper case.
      ; Else convert to lower case. Spaces or tabs after these marks are ignored.
 
      ;Detect current characters and ignore if necessary
      ${If} $6 == " "
      ${OrIf} $6 == "$\t"
        Goto IgnoreLetter
      ${EndIf}
 
      ;Detect last characters and convert
      ${If} $7 == "."
      ${OrIf} $7 == "!"
      ${OrIf} $7 == "?"
      ${OrIf} $7 == ""
        System::Call "User32::CharUpper(t r6 r6)i"
      ${Else}
        System::Call "User32::CharLower(t r6 r6)i"
      ${EndIf}
    ${ElseIf} $1 == "<>"
 
      ;Switch Case:
      ;------------------
      ; Switch all characters cases to their inverse case.
 
      ;Use "IsCharUpper" for the job
      System::Call "*(&t1 r6) i .r8"
      System::Call "*$8(&i1 .r7)"
      System::Free $8
      System::Call "user32::IsCharUpper(i r7) i .r8"
 
      ;Verify "IsCharUpper" result and convert the character
      ${If} $8 = 0
        System::Call "User32::CharUpper(t r6 r6)i"
      ${Else}
        System::Call "User32::CharLower(t r6 r6)i"
      ${EndIf}
    ${EndIf}
 
    ;Write the character to "LastChar"
    StrCpy $7 $6
 
    IgnoreLetter:
    ;Add this character to "ResultStr"
    StrCpy $5 `$5$6`
  ${Next}
 
  StrCase_End:
 
/*After this point:
  ------------------------------------------
  $0 = ResultVar (output)*/
 
  ; Copy "ResultStr" to "ResultVar"
  StrCpy $0 $5
 
  ;Return output to user
  Pop $8
  Pop $7
  Pop $6
  Pop $5
  Pop $4
  Pop $3
  Pop $2
  Pop $1
  Exch $0
FunctionEnd
Function StrTrimNewLines
/*After this point:
  ------------------------------------------
  $R0 = String (input)
  $R1 = TrimCounter (temp)
  $R2 = Temp (temp)*/
 
  ;Get input from user
  Exch $R0
  Push $R1
  Push $R2
 
  ;Initialize trim counter
  StrCpy $R1 0
 
  loop:
  ;Subtract to get "String"'s last characters
  IntOp $R1 $R1 - 1
 
  ;Verify if they are either $\r or $\n
  StrCpy $R2 $R0 1 $R1
  ${If} $R2 == '$\r'
  ${OrIf} $R2 == '$\n'
    Goto loop
  ${EndIf}
 
  ;Trim characters (if needed)
  IntOp $R1 $R1 + 1
  ${If} $R1 < 0
    StrCpy $R0 $R0 $R1
  ${EndIf}
 
/*After this point:
  ------------------------------------------
  $R0 = ResultVar (output)*/
 
  ;Return output to user
  Pop $R2
  Pop $R1
  Exch $R0
FunctionEnd
;--------------------------------
;Descriptions
 
  ;Assign language strings to sections
  !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
    !insertmacro MUI_DESCRIPTION_TEXT ${SecInstall} $(DESC_SecInstall)
    !insertmacro MUI_DESCRIPTION_TEXT ${NXClient} $(DESC_NXClient)
    !insertmacro MUI_DESCRIPTION_TEXT ${PythonLookup} $(DESC_PythonLookup)
  !insertmacro MUI_FUNCTION_DESCRIPTION_END
  
  
;--------------------------------
;Uninstaller Section
Section "Uninstall"
  StrCmp $LANGUAGE ${LANG_HUNGARIAN} 0 +4
    IfFileExists "$SMPROGRAMS\${Company}\L�togasd meg a ${AppUrlName}-t.url" 0 +2
      Delete "$SMPROGRAMS\${Company}\L�togasd meg a ${AppUrlName}-t.url"
    Goto +3
    IfFileExists "$SMPROGRAMS\${Company}\Visit the ${AppUrlName}.url" 0 +2
      Delete "$SMPROGRAMS\${Company}\Visit the ${AppUrlName}.url"
  
  IfFileExists "$SMPROGRAMS\${Company}\${AppName}\*.*" 0 +2
    RMDir /r "$SMPROGRAMS\${Company}\${AppName}"

  IfFileExists "$SMPROGRAMS\${Company}\*.*" +2 0
    RMDir /r "$SMPROGRAMS\${Company}"
    
  ExecWait '"$INSTDIR\uninstaller\uninstall.cmd" "$INSTDIR" ${Show_output} >"$INSTDIR\uninstall.log" 2>"$INSTDIR\uninstall_error.log"'
    
  IfFileExists "$INSTDIR\uninstaller\*.*" 0 +2
    RMDir /r "$INSTDIR\uninstaller"
  IfFileExists "$INSTDIR\.rdp\*.*" 0 +2
    RMDir /r "$INSTDIR\.rdp"
  IfFileExists "$INSTDIR\client.log" 0 +2
    Delete "$INSTDIR\client.log"
  IfFileExists "$INSTDIR\cloud.py" 0 +2
    Delete "$INSTDIR\cloud.py"
  IfFileExists "$INSTDIR\cloud_connect_from_windows.py" 0 +2
    Delete "$INSTDIR\cloud_connect_from_windows.py"
  IfFileExists "$INSTDIR\nxkey.py" 0 +2
    Delete "$INSTDIR\nxkey.py"
  IfFileExists "$INSTDIR\OrderedDict.py" 0 +2
    Delete "$INSTDIR\OrderedDict.py"
  IfFileExists "$INSTDIR\putty.exe" 0 +2
    Delete "$INSTDIR\putty.exe"
  IfFileExists "$INSTDIR\win_install.py" 0 +2
    Delete "$INSTDIR\win_install.py"
  IfFileExists "$INSTDIR\windowsclasses.py" 0 +2
    Delete "$INSTDIR\windowsclasses.py"
  IfFileExists "$INSTDIR\windowsclasses.pyc" 0 +2
    Delete "$INSTDIR\windowsclasses.pyc"
 
  IfFileExists "$INSTDIR\${AppUninstaller}" 0 +2
    Delete "$INSTDIR\${AppUninstaller}"

  StrCmp $INSTDIR "${DefaulLocation}" 0 +2
    RMDir /r "$INSTDIR"
SectionEnd
;--------------------------------
;Uninstaller Functions
Function un.onInit
  ClearErrors
  ReadRegStr $0 HKCU "Software\${Company} ${AppName}" "install_directory"
  ${If} ${Errors}
    ${IF} $INSTDIR == ""
      StrCpy $INSTDIR "$LOCALAPPDATA\CIRCLE"
    ${ENDIF}
  ${Else}
    ${IF} $0 == ""
       StrCpy $INSTDIR "$LOCALAPPDATA\CIRCLE"
    ${ELSE}
       StrCpy $INSTDIR $0
    ${ENDIF}
  ${EndIf}
  ${If} ${RunningX64}
        ${DisableX64FSRedirection}
        SetRegView 64
  ${EndIf}
  !insertmacro MUI_UNGETLANGUAGE
FunctionEnd