Skip to content

Instantly share code, notes, and snippets.

@heri16
Last active June 5, 2018 03:51
Show Gist options
  • Save heri16/2f335efefe76e6f69f22449cab78fd48 to your computer and use it in GitHub Desktop.
Save heri16/2f335efefe76e6f69f22449cab78fd48 to your computer and use it in GitHub Desktop.
AutoHotKey Server to Automate Export/Import of XML data into CPSSoft RENE Admin via HTTP API.
#Persistent
#NoEnv ; Avoids checking empty variables to see if they are environment variables
#KeyHistory 0 ; Disable key history
#SingleInstance force ; Skips the dialog box and replaces the old instance automatically
SetBatchLines, -1 ; Never sleep (i.e. have the script run at maximum speed)
SendMode, Input ; Use faster and more reliable send method
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory
CoordMode, Mouse, Screen ; Make 0,0 the top-left of screen
SetTitleMatchMode, 3 ; Allow only exact window title matches
FileEncoding, UTF-8 ; Use UTF-8 file encoding
; Enable Console-based Script
;LibConDebug := 1
;FreeConsole()
;SmartStartConsole()
paths := {}
paths["/file/put"] := Func("PutFile")
paths["/menu/exim"] := Func("OpenImportExportMenu")
paths["/import/xml"] := Func("ImportXmlData")
paths["/import/logs"] := Func("WaitImportLogs")
paths["/"] := Func("HelloWorld")
paths["404"] := Func("NotFound")
paths["/logo"] := Func("Logo")
server := new HttpServer()
server.LoadMimes(A_ScriptDir . "/mime.types")
server.SetPaths(paths)
server.Serve(8001)
Puts("Ready.")
return
Logo(ByRef req, ByRef res, ByRef server) {
server.ServeFile(res, A_ScriptDir . "/logo.png")
res.status := 200
}
NotFound(ByRef req, ByRef res) {
res.SetBodyText("Page not found")
}
HelloWorld(ByRef req, ByRef res) {
res.SetBodyText("<html><body><img src='./logo'/><br/>Hello World</body></html>")
res.status := 200
}
WaitImportLogs(ByRef req, ByRef res) {
global winMainHwnd
global filePattern
Puts("WaitImportLogs:")
if winMainHwnd is not integer
{
return HttpError(res, "Main ReneAdmin window is unknown. Please do /menu/exim first.")
}
WinGet, progPID, PID, ahk_id %winMainHwnd%
Print("WaitingImportCompleteDialog...")
Loop {
Print(".")
WinWait, ahk_class TfrmDialog ahk_pid %progPID%,, 1
} Until ErrorLevel == 0
importCompleteHwnd := WinExist("")
NewLine()
Puts("ClosingImportCompleteDialog...")
ControlClick, TPanel2, ahk_id %importCompleteHwnd%
Puts("CheckingOfflineForm...")
ControlGet, offlineFormHwnd, Hwnd,, TfrmExportHistory1, ahk_id %winMainHwnd%
if (!offlineFormHwnd) {
return HttpError(res, "ReneAdmin Accurate Offline Form could not be found")
}
Puts("SelectingOfflineFilters...")
ControlClick, TAdvOfficeCheckBox2, ahk_id %offlineFormHwnd%
ControlClick, TAdvOfficeCheckBox3, ahk_id %offlineFormHwnd%
ControlClick, TAdvOfficeCheckBox4, ahk_id %offlineFormHwnd%
ControlClick, TAdvOfficeCheckBox5, ahk_id %offlineFormHwnd%
Puts("ClickingRefreshToolbar..")
ControlGet, offlineToolBarHwnd, Hwnd,, TToolBar1, ahk_id %offlineFormHwnd%
ControlClick, X265 Y10, ahk_id %offlineToolBarHwnd%
Puts("SelectingFirstRow...")
Sleep, 2000
ControlSend, TtiInternalVirtualTree1, {Down}, ahk_id %offlineFormHwnd%
Puts("ClickingShowLogToolbar...")
ControlClick, X180 Y10, ahk_id %offlineToolBarHwnd%
Puts("DeselectingOfflineFilters...")
ControlClick, TAdvOfficeCheckBox2, ahk_id %offlineFormHwnd%
ControlClick, TAdvOfficeCheckBox3, ahk_id %offlineFormHwnd%
ControlClick, TAdvOfficeCheckBox4, ahk_id %offlineFormHwnd%
ControlClick, TAdvOfficeCheckBox5, ahk_id %offlineFormHwnd%
Puts("WaitingShowLogWindow...")
WinWait, ahk_class TfrmExportLog ahk_pid %progPID%,, 5
if (ErrorLevel) {
return HttpError(res, "ReneAdmin Offline SeeLog Window could not be found")
}
showLogWindow := WinExist("")
ControlGetText, logsInHistory, TMemo1, ahk_id %showLogWindow%
ControlSend, TAdvSmoothPanel1, {Alt Down}t{Alt Up}, ahk_id %showLogWindow%
Puts("ArchivingXmlFile...")
FileMove, %filePattern%, ..\Data\Archive
Puts("FetchedImportLogs.")
importLogs := logsInHistory
res.SetBodyText(logsInHistory)
res.status := 200
}
OpenImportExportMenu(ByRef req, ByRef res) {
global winMainHwnd
Puts("OpenImportExportMenu:")
WriteReneSetupConfig({ PATHDATABASE: "3002.FDB" })
startResult := StartWrappedProgram()
if startResult is not integer
{
return HttpError(res, startResult)
}
progPID := startResult
DetectHiddenWindows, On
winMainHwnd := WinExist(Format("ahk_class TfrmMain ahk_pid {}", progPID))
if (!winMainHwnd) {
Puts("WaitingLoginWindow...")
WinWait, ahk_class TfrmAdminLogin ahk_pid %progPID%, , 10
if (!ErrorLevel) {
secretPin := DecryptSecretPin(".\pin.txt")
ControlSetText, TEdit1, %secretPin%
ControlSend, TEdit1, {Enter}
}
Puts("WaitingMainWindow...")
WinWait, ahk_class TfrmMain ahk_pid %progPID%, , 15
if (ErrorLevel) {
return HttpError(res, "Main Window could not be found")
}
winMainHwnd := WinExist("")
}
DetectHiddenWindows, Off
WinShow, ahk_id %winMainHwnd%
WinMinimize, ahk_id %winMainHwnd%
retry := 50
While (!toolBarPagerHwnd && retry > 0)
{
Puts("WaitingToolBarPager...")
Sleep, 100
ControlGet, toolBarPagerHwnd, Hwnd,, TAdvToolBarPager1, ahk_id %winMainHwnd%
retry -= 1
}
if (!toolBarPagerHwnd)
{
return HttpError(res, "ReneAdmin ToolBarPager Control could not be found")
}
retry := 30
While (!isToolBarPagerVisible && retry > 0)
{
Puts("WaitingToolBarPagerVisible...")
Sleep, 200
ControlGet, isToolBarPagerVisible, Visible,,, ahk_id %toolBarPagerHwnd%
retry -= 1
}
if (!isToolBarPagerVisible) {
return HttpError(res, "ReneAdmin ToolBarPager Control did not become visible")
}
; Move right to third tab of ToolBarPager
ControlFocus, , ahk_id %toolBarPagerHwnd%
ControlSend,, {Right}{Right}, ahk_id %toolBarPagerHwnd%
retry := 30
While (!accurateBtnHwnd && retry > 0)
{
Puts("WaitingAccurateButton...")
Sleep, 100
ControlGet, accurateBtnHwnd, Hwnd,, ACCURATE 4, ahk_id %toolBarPagerHwnd%
retry -= 1
}
if (!accurateBtnHwnd) {
return HttpError(res, "ReneAdmin AccurateButton Control was not found")
}
; Move back to first tab of ToolBarPager
ControlSend,, {Left}{Left}, ahk_id %toolBarPagerHwnd%
;ControlFocus,, ahk_id %accurateBtnHwnd%
;ControlSend,, {Space}, ahk_id %accurateBtnHwnd%
;Puts("OpeningOnlineForm...")
;ControlClick, X90 Y15, ahk_id %accurateBtnHwnd%
;WinWait, ahk_class #32768 ahk_pid %progPID%,, 5
;if (ErrorLevel) {
; return HttpError(res, "DropDown could not be found")
;}
;ControlSend,, o
;retry := 50
;While (!onlineFormHwnd && retry > 0)
;{
; Puts("WaitingOnlineForm...")
; Sleep, 100
; ControlGet, onlineFormHwnd, Hwnd,, TfrmAccurateAgentQueue1, ahk_id %winMainHwnd%
; retry -= 1
;}
;if (!onlineFormHwnd) {
; return HttpError(res, "ReneAdmin Accurate Online Form could not open")
;}
Puts("OpeningOfflineForm...")
ControlClick, X90 Y15, ahk_id %accurateBtnHwnd%
WinWait, ahk_class #32768 ahk_pid %progPID%,, 5
if (ErrorLevel) {
return HttpError(res, "DropDown could not be found")
}
ControlSend,, f
retry := 50
While (!offlineFormHwnd && retry > 0)
{
Puts("WaitingOfflineForm...")
Sleep, 100
ControlGet, offlineFormHwnd, Hwnd,, TfrmExportHistory1, ahk_id %winMainHwnd%
retry -= 1
}
if (!offlineFormHwnd) {
return HttpError(res, "ReneAdmin Accurate Offline Form could not open")
}
Puts("OpenedForms.")
res.SetBodyText("Opened")
res.status := 200
}
ImportXmlData(ByRef req, ByRef res) {
global winMainHwnd
global filePattern
Puts("ImportXmlData:")
filenameUnsafe := req.queries["filename"]
SplitPath, filenameUnsafe, filename
if (!filename) {
res.SetBodyText("Invalid Input: filename required in querystring")
res.status := 400
return
}
if winMainHwnd is not integer
{
return HttpError(res, "Main ReneAdmin window is unknown. Please do /menu/exim first.")
}
WinGet, progPID, PID, ahk_id %winMainHwnd%
Puts("CheckingOfflineForm...")
ControlGet, offlineFormHwnd, Hwnd,, TfrmExportHistory1, ahk_id %winMainHwnd%
if (!offlineFormHwnd) {
return HttpError(res, "ReneAdmin Accurate Offline Form could not be found")
}
Puts("ClickingImportToolbar...")
ControlGet, offlineToolBarHwnd, Hwnd,, TToolBar1, ahk_id %offlineFormHwnd%
ControlClick, X100 Y10, ahk_id %offlineToolBarHwnd%
Puts("WaitingImportWindow...")
WinWait, ahk_class TfrmImportAcc ahk_pid %progPID%,, 10
if (ErrorLevel) {
return HttpError(res, "Import Window could not be found")
}
importFormHwnd := WinExist("")
Puts("InputImportFilePath...")
filePattern := Format("..\Data\{}", filename)
Loop, Files, %filePattern%
{
filePath := A_LoopFileLongPath
ControlSetText, TEdit1, %filePath%, ahk_id %importFormHwnd%
ControlSend, TEdit1, {Enter}, ahk_id %importFormHwnd%
Break
}
if (!filePath) {
return HttpError(res, Format("{} file could not be found", filename))
}
retry := 40
While (!importMemoHwnd && retry > 0)
{
Puts("WaitingImportMemo...")
Sleep, 500
ControlGet, importMemoHwnd, Hwnd,, TMemo1, ahk_id %importFormHwnd%
retry -= 1
}
if (!importMemoHwnd)
{
return HttpError(res, "ReneAdmin ImportMemo Control could not be found")
}
retry := 10
While (!isImportMemoVisible && retry > 0)
{
Puts("WaitingImportMemoVisible...")
Sleep, 100
ControlGet, isImportMemoVisible, Visible,,, ahk_id %importMemoHwnd%
retry -= 1
}
if (!isImportMemoVisible) {
return HttpError(res, "ReneAdmin ImportMemo Control did not become visible within timeout")
}
Puts("ClickingImportButton...")
ControlGetText, importMemoText,, ahk_id %importMemoHwnd%
ControlSend, TAdvSmoothPanel1, {Alt Down}i{Alt Up}, ahk_id %importFormHwnd%
Puts("StartedImport.")
res.SetBodyText(importMemoText)
res.status := 200
}
PutFile(ByRef req, ByRef res) {
if (req.method != "PUT") {
res.headers["Allow"] := "PUT"
res.status := 405
return
}
filenameUnsafe := req.queries["filename"]
SplitPath, filenameUnsafe, filename
if (!filename) {
filename := CreateUUID()
;res.SetBodyText("Invalid QueryString, filename required")
;res.status := 400
;return
}
Puts(Format("File {}: {} bytes", filename, StrLen(req.body)))
file := FileOpen(Format("..\Data\{}", filename), "w")
file.Write(req.body)
file.Close()
res.SetBodyText(filename)
res.status := 200
}
WriteReneSetupConfig(config) {
;Puts("WriteReneSetupConfig")
FileRead, configTemplate, .\hdsetup.xml.tpl
For key, value in config
{
configTemplate := RegExReplace(configTemplate, Format("<{1}>.*</{1}>", key), Format("<{1}>{2}</{1}>", key, value))
}
configFile := FileOpen(Format("{}\RENE2\hdsetup.xml", A_AppData), "w")
configFile.Write(configTemplate)
configFile.Close()
}
StartWrappedProgram() {
;Puts("StartWrappedProgram")
; Ensure reneadmin.exe is running under our current user session
Process, Exist, reneadmin.exe ; check to see if MTAutoDown.exe is running
existingPID := ErrorLevel
if (existingPID)
{
;Puts("ReuseReneAdminStep")
DetectHiddenWindows, On
isMainWinExist := WinExist("ahk_exe reneadmin.exe")
DetectHiddenWindows, Off
if (isMainWinExist)
{
progPID := existingPID
}
else
{
;Process, Close, reneadmin.exe ; close all other running processes in other desktops
;isOk := ErrorLevel
;if (!isOk) {
; return "reneadmin.exe running but could not be closed"
;}
}
}
if (!progPID)
{
;Puts("StartReneAdminStep")
IfExist, %A_ProgramsCommon%\CPSSoft\RENE2\RENE Administration.lnk
{
Run, %A_ProgramsCommon%\CPSSoft\RENE2\RENE Administration.lnk, , UseErrorLevel, progPID
if (A_LastError > 0) {
return Format("RENE Administration.lnk could not be launched due to Error Code {}", A_LastError)
}
}
Else
{
return "RENE Administration.lnk could not be found"
}
}
return progPID
}
DecryptSecretPin(pinFile) {
if (GetConsoleHandle())
{
restartConsoleWindow := true
}
shell := ComObjCreate("WScript.Shell")
exec := shell.Exec("powershell -WindowStyle Hidden -NonInteractive -NoLogo -Command -")
commands =
(
$secpass = Get-Content "%pinFile%" | ConvertTo-SecureString
$cred = New-Object System.Management.Automation.PSCredential ("pin", $secpass)
$cred.GetNetworkCredential().Password
exit
)
exec.StdIn.WriteLine(commands)
output := exec.StdOut.ReadAll()
if (restartConsoleWindow) {
SmartStartConsole()
}
return Trim(output, " `t`n`r")
}
HttpError(res, msg) {
Puts(msg)
res.SetBodyText(Format("Error: {}", msg))
res.status := 500
}
FileTruncate(filename)
{
hFile := DllCall( "CreateFile", Str,filename, UInt,0x40000000, UInt,3, UInt,0, UInt,5, UInt,0, UInt,0 )
DllCall( "CloseHandle", UInt,hFile ) ; Thanks tonne !
return hFile > 0 ? 1 : hFile
}
CreateUUID()
{
VarSetCapacity(UUID, 16, 0)
if (DllCall("rpcrt4.dll\UuidCreate", "ptr", &UUID) != 0)
return (ErrorLevel := 1) & 0
if (DllCall("rpcrt4.dll\UuidToString", "ptr", &UUID, "uint*", suuid) != 0)
return (ErrorLevel := 2) & 0
return StrGet(suuid), DllCall("rpcrt4.dll\RpcStringFree", "uint*", suuid)
}
UuidEqual(uuid1, uuid2)
{
return DllCall("rpcrt4.dll\UuidEqual", "ptr", &uuid1, "ptr", &uuid2, "ptr", &RPC_S_OK)
}
#include %A_ScriptDir%\LibCon.ahk
#include %A_ScriptDir%\AHKhttp.ahk
#include %A_ScriptDir%\AHKsock.ahk
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment