AutoHotkey Community

It is currently May 26th, 2012, 3:11 am

All times are UTC [ DST ]




Post new topic Reply to topic  [ 25 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: February 20th, 2008, 4:54 am 
Offline

Joined: May 24th, 2007, 3:45 am
Posts: 1121
Update: Version 1.2
Accepts Windows network addresses and domain names (not just IPs).
Replaced default tray menus with less cluttered version.


Version 1.1
New command for displaying a menu.

I wanted to make something based on this TCP/IP sample. Either this or a chat seemed like the obvious choices. I wanted to create something that is:
  1. Different enough from professional apps like RealVNC that it has it's own niche.
  2. Not too great a security risk or backdoor-like.
So this is what I cam out with.

Image

All of the commands are on the server. So the client can only perform actions you specifically allow (in theory). It works somewhat like the Simple Mouse Gesture script in that you create new commands by adding labels to be bottom of the server script. Without further ado...

Client Script
Code:
;AHK Remote Client v1.2

#SingleInstance Force
#NoEnv
SendMode Input

NetworkAddress = 127.0.0.1 ;127.0.0.1 means local machine (so does blank).
NetworkPort    = 8257
PromptForAddy  = 1         ;Allows the user to supply another address if desired.
TestTimout     = 1000      ;ms, Blank means don't pre-test the address.
MaxDataLength  = 4096      ;Longest message that can be recieved.
MaxGuiRows     = 10
ButtonSize     = 128       ;Blank means auto.

Menu TRAY, Tip, AHK Remote
Menu TRAY, Icon, SHELL32.DLL, 121
Menu TRAY, NoStandard
If (NOT A_IsCompiled)
{
   Menu TRAY, Add, &Edit, TrayEdit
   Menu TRAY, Add
}
Menu TRAY, Add, &Reload, TrayReload
Menu TRAY, Add, E&xit, TrayExit

If PromptForAddy
{
   Gui Add, Text, w64 Right, Address:
   Gui Add, Edit, w100 yp-4 x+8 vNetworkAddress, %NetworkAddress%
   Gui Add, Text, xm w64 Right, Port:
   Gui Add, Edit, w100 yp-4 x+8 vNetworkPort, %NetworkPort%
   Gui Add, Button, gGetStarted Default, Connect
   Gui Show,, Enter Address
   Return
}
GetStarted:
Gui Submit

if (NetworkAddress = "")
   NetworkAddress := "127.0.0.1"
If (NOT TestTimout)
   TestTimout := 0
NeedIP := !RegExMatch(NetworkAddress, "^(\d+\.){3}\d+$")

If (TestTimout OR NeedIP)
{
   ;Use Ping to check if the address is reachable, we can also get the IP address this way.
   RunWait %ComSpec% /C Ping -n 1 -w %TestTimout% %NetworkAddress% > getpingtestip.txt,, Hide
   If (ErrorLevel AND TestTimout)
   {
      MsgBox %NetworkAddress% cannot be reached.
      FileDelete getpingtestip.txt
      ExitApp
   }
   If NeedIP
   {
      Loop, Read, getpingtestip.txt
      {
         If RegExMatch(A_LoopReadLine, "(?<=\[)(\d+\.){3}\d+(?=\])", NetworkAddress)
           Break
      }
   }
   FileDelete getpingtestip.txt
}

Menu PopUp, Add, Dummy, HandleMenu ;So the menu exists.

If (ButtonSize != "")
   ButtonSize := "w" . ButtonSize

;v v v v v v v v v v v v v v v v v v v
OnExit DoExit

MainSocket := PrepareSocket(NetworkAddress, NetworkPort)
If (MainSocket = -1)
   ExitApp ;failed

DetectHiddenWindows On
Process Exist
MainWindow := WinExist("ahk_class AutoHotkey ahk_pid " . ErrorLevel)
DetectHiddenWindows Off

;^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
;FD_READ + FD_CLOSE + FD_WRITE = 35
If DllCall("Ws2_32\WSAAsyncSelect", "UInt", MainSocket, "UInt", MainWindow, "UInt", 5555, "Int", 35)
;v v v v v v v v v v v v v v v v v v v
{
    MsgBox % "WSAAsyncSelect() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
    ExitApp
}

OnMessage(5555, "ReceiveData", 99) ;Allow 99 (i.e. lots of) threads.

Return

PrepareSocket(IPAddress, Port)
{
   VarSetCapacity(wsaData, 32)
   Result := DllCall("Ws2_32\WSAStartup", "UShort", 0x0002, "UInt", &wsaData)
   If ErrorLevel
   {
      MsgBox WSAStartup() could not be called due to error %ErrorLevel%. Winsock 2.0 or higher is required.
      return -1
   }
   If Result  ; Non-zero, which means it failed (most Winsock functions return 0 upon success).
   {
      MsgBox % "WSAStartup() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
      return -1
   }

   ;AF_INET = 2   SOCK_STREAM = 1   IPPROTO_TCP = 6
   Socket := DllCall("Ws2_32\socket", "Int", 2, "Int", 1, "Int", 6)
   If (Socket = -1)
   {
      MsgBox % "Socket() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
      return -1
   }

   VarSetCapacity(SocketAddress, 16)
   InsertInteger(2, SocketAddress, 0, 2) ; AF_INET = 2
   InsertInteger(DllCall("Ws2_32\htons", "UShort", Port), SocketAddress, 2, 2)   ; sin_port
   InsertInteger(DllCall("Ws2_32\inet_addr", "Str", IPAddress), SocketAddress, 4, 4)   ; sin_addr.s_addr
;^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^

   If DllCall("Ws2_32\connect", "UInt", Socket, "UInt", &SocketAddress, "Int", 16)
   {
      Result := DllCall("Ws2_32\WSAGetLastError")
      If (Result = 10061)
         MsgBox Connection Refused. That probably means the server script is not running.
      Else
         MsgBox % "Connect() indicated Winsock error " . Result
      return -1
   }
   
   Return Socket
}

ReceiveData(wParam, lParam)
{
   Global MaxGuiRows, ButtonSize, MaxDataLength, MainSocket, MenuChoice

;v v v v v v v v v v v v v v v v v v v
   VarSetCapacity(ReceivedData, MaxDataLength, 0)
   ReceivedDataLength := DllCall("Ws2_32\recv", "UInt", wParam, "Str", ReceivedData, "Int", MaxDataLength, "Int", 0)
   If (ReceivedDataLength = 0)  ; The connection was gracefully closed
      Return NormalClose()
   if ReceivedDataLength = -1
   {
      WinsockError := DllCall("Ws2_32\WSAGetLastError")
      If (WinsockError = 10035)  ; No more data to be read
         Return 1
      If WinsockError = 10054 ; Connection closed
         Return NormalClose()
      MsgBox % "Recv() indicated Winsock error " . WinsockError
      ExitApp
   }

   Command := SubStr(ReceivedData, 1, 10)
   ReceivedData := SubStr(ReceivedData, 11)
;^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^

   If (Command = "ARCOMLIST:")
   {
      Gui Destroy
      Loop Parse, ReceivedData, %A_Space%
      {
         StringReplace ButtonName, A_Loopfield, _, %A_Space%, All
         If (Mod(A_Index, MaxGuiRows) = 0)
            Options .= "ym "
         Gui Add, Button, %ButtonSize% gHandleButton %Options%, %ButtonName%
         Options =
      }
      Gui Show,, AHK Remote
   }
   Else If (Command = "ARSHOWTXT:")
   {
      Gui 2:Destroy
      Gui 2:Add, Edit, Multi w500, %ReceivedData%
      Gui 2:+ToolWindow +Owner1
      Gui 2:Show,, AHK Remote
   }
   Else If (Command = "ARMESSAGE:")
   {
      Gui +OwnDialogs
      MsgBox,, AHK Remote, %ReceivedData%
   }
   Else If (Command = "ARYESORNO:")
   {
      Gui +OwnDialogs
      MsgBox 36, AHK Remote, %ReceivedData%
      IfMsgBox Yes
         SendData(MainSocket, "ARESPONSE:YES")
      Else
         SendData(MainSocket, "ARESPONSE:NO")
   }
   Else If (Command = "ARGETINFO:")
   {
      Gui +OwnDialogs
      InputBox Result, AHK Remote, %ReceivedData%,,, 130
      If (ErrorLevel OR Result = "")
         SendData(MainSocket, "ARESPONSE:CANCEL")
      Else
         SendData(MainSocket, "ARESPONSE:" . Result)
   }
   Else If (Command = "ARPASWORD:")
   {
      Gui +OwnDialogs
      InputBox Result, AHK Remote, Password required., Hide,, 110
      If ErrorLevel
         SendData(MainSocket, "ARESPONSE:CANCEL")
      Else
         SendData(MainSocket, "ARESPONSE:" . RC4txt2hex("OPENSESAME", Result . ReceivedData))
   }
   Else If (Command = "ARPOPMENU:")
   {
      Menu PopUp, DeleteAll
      Loop Parse, ReceivedData, |
         Menu PopUp, Add, %A_LoopField%, HandleMenu
      MenuChoice := 0
      Menu PopUp, Show
      SendData(MainSocket, "ARESPONSE:" . MenuChoice)
   }

   Return 1
}

NormalClose()
{
   ExitApp
   Return 1
}

;v v v v v v v v v v v v v v v v v v v
SendData(Socket, Data)
{
   SendRet := DllCall("Ws2_32\send", "UInt", Socket, "Str", Data, "Int", StrLen(Data), "Int", 0)
   If (SendRet = -1)
      MsgBox % "Send() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
   Return SendRet
}

;By Laszlo, used by the password function.
RC4txt2hex(Data,Pass) {
   Format := A_FormatInteger
   SetFormat Integer, Hex
   b := 0, j := 0
   VarSetCapacity(Result,StrLen(Data)*4)
   Loop 256 {
      a := A_Index - 1
      Key%a% := Asc(SubStr(Pass, Mod(a,StrLen(Pass))+1, 1))
      sBox%a% := a
   }
   Loop 256 {
      a := A_Index - 1
      b := b + sBox%a% + Key%a%  & 255
      T := sBox%a%
      sBox%a% := sBox%b%
      sBox%b% := T
   }
   Loop Parse, Data
   {
      i := A_Index & 255
      j := sBox%i% + j  & 255
      k := sBox%i% + sBox%j%  & 255
      Result .= Asc(A_LoopField)^sBox%k%
   }
   Result := RegExReplace(Result, "0x(.)(?=0x|$)", "0$1")
   StringReplace Result, Result, 0x,,All
   SetFormat Integer, %Format%
   Return Result
}

InsertInteger(pInteger, ByRef pDest, pOffset = 0, pSize = 4)
{
   Loop %pSize%  ; Copy each byte in the integer into the structure as raw binary data.
      DllCall("RtlFillMemory", "UInt", &pDest + pOffset + A_Index-1, "UInt", 1, "UChar", pInteger >> 8*(A_Index-1) & 0xFF)
}

GuiClose:
ExitApp

DoExit:
TrayExit:
DllCall("Ws2_32\WSACleanup")
ExitApp

TrayEdit:
Edit
Return

TrayReload:
Reload
Return

;^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^

HandleButton:
StringReplace CommandName, A_GuiControl, %A_Space%, _, All
SendData(MainSocket, "ARCOMMAND:" . CommandName)
Return

HandleMenu:
MenuChoice := A_ThisMenuItemPos
Return

Server Script
Code:
;AHK Remote Server v1.2

#SingleInstance Force
#NoEnv
SendMode Input

NetworkAddress = 0.0.0.0 ;Listen address, 0.0.0.0 = any
NetworkPort    = 8257    ;Listen port

MaxDataLength  = 4096    ;Longest message that can be recieved.

Menu TRAY, Tip, AHK Remote Server`n%A_IPAddress1%
Menu TRAY, Icon, SHELL32.DLL, 125
Menu TRAY, NoStandard
If A_IsCompiled ;The self-reading trick won't work for compiled scripts.
   CommandList = Quit Volume_Up Volume_Down Mute ;sample hard-coded list
Else
{
   LabelStart := False
   Loop Read, %A_ScriptFullPath%
   {
      If (NOT LabelStart)
      {
         If InStr(A_LoopReadLine, "===" . "Begin Custom Labels" . "===")
            LabelStart := True
         Else
            Continue
      }
      If RegExMatch(A_LoopReadLine, "^[^\s;]\S*(?=:\s*$)", LabelName)
         CommandList .= " " . LabelName
   }
   CommandList := SubStr(CommandList, 2)
   Menu TRAY, Add, &Edit, TrayEdit
   Menu TRAY, Add, &Copy Command List, TrayCopy
   Menu TRAY, Add
}
Menu TRAY, Add, No Connection, TrayDisconnect
Menu TRAY, Disable, No Connection
Menu TRAY, Add, &Reload, TrayReload
Menu TRAY, Add, E&xit, TrayExit
RunningCommands := " "

;v v v v v v v v v v v v v v v v v v v
OnExit DoExit

MainSocket := PrepareSocket(NetworkAddress, NetworkPort)
If (MainSocket = -1)
   ExitApp ;failed

DetectHiddenWindows On
Process Exist
MainWindow := WinExist("ahk_class AutoHotkey ahk_pid " . ErrorLevel)
DetectHiddenWindows Off

;^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
;FD_READ + FD_CLOSE + FD_ACCEPT = 41
If DllCall("Ws2_32\WSAAsyncSelect", "UInt", MainSocket, "UInt", MainWindow, "UInt", 5555, "Int", 41)
;v v v v v v v v v v v v v v v v v v v
{
    MsgBox % "WSAAsyncSelect() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
    ExitApp
}

OnMessage(5555, "ReceiveData", 99) ;Allow 99 (i.e. lots of) threads.

Return

PrepareSocket(IPAddress, Port)
{
   VarSetCapacity(wsaData, 32)
   Result := DllCall("Ws2_32\WSAStartup", "UShort", 0x0002, "UInt", &wsaData)
   If ErrorLevel
   {
      MsgBox WSAStartup() could not be called due to error %ErrorLevel%. Winsock 2.0 or higher is required.
      return -1
   }
   If Result  ; Non-zero, which means it failed (most Winsock functions return 0 upon success).
   {
      MsgBox % "WSAStartup() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
      return -1
   }

   ;AF_INET = 2   SOCK_STREAM = 1   IPPROTO_TCP = 6
   Socket := DllCall("Ws2_32\socket", "Int", 2, "Int", 1, "Int", 6)
   If (Socket = -1)
   {
      MsgBox % "Socket() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
      return -1
   }

   VarSetCapacity(SocketAddress, 16)
   InsertInteger(2, SocketAddress, 0, 2) ; AF_INET = 2
   InsertInteger(DllCall("Ws2_32\htons", "UShort", Port), SocketAddress, 2, 2)   ; sin_port
   InsertInteger(DllCall("Ws2_32\inet_addr", "Str", IPAddress), SocketAddress, 4, 4)   ; sin_addr.s_addr
;^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^

   If DllCall("Ws2_32\bind", "UInt", Socket, "UInt", &SocketAddress, "Int", 16)
   {
      MsgBox % "Bind() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
      return -1
   }
   If DllCall("Ws2_32\listen", "UInt", Socket, "UInt", "SOMAXCONN")
   {
      MsgBox % "Listen() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
      return -1
   }
   
   Return Socket
}

ReceiveData(wParam, lParam)
{
   Global MaxDataLength, OutgoingSocket, CommandList, RunningCommands, ClientResponse
   Event := lParam & 0xFFFF

   If (Event = 8) ;FD_ACCEPT = 8
   {
      If (OutgoingSocket > 0)
         NormalClose() ;Close OutgoingSocket
      OutgoingSocket := DllCall("Ws2_32\accept", "UInt", wParam, "UInt", &SocketAddress, "Int", 0)
      If (OutgoingSocket < 0)
         MsgBox % "Accept() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
      Else
      {
         SendData(OutgoingSocket, "ARCOMLIST:" . CommandList)
         Menu TRAY, Rename, No Connection, &Disconnect
         Menu TRAY, Enable, &Disconnect
         Menu TRAY, Tip, AHK Remote Server`nConnected!
      }
      Return 1
   }

;v v v v v v v v v v v v v v v v v v v
   VarSetCapacity(ReceivedData, MaxDataLength, 0)
   ReceivedDataLength := DllCall("Ws2_32\recv", "UInt", wParam, "Str", ReceivedData, "Int", MaxDataLength, "Int", 0)
   If (ReceivedDataLength = 0)  ; The connection was gracefully closed
      Return NormalClose()
   if ReceivedDataLength = -1
   {
      WinsockError := DllCall("Ws2_32\WSAGetLastError")
      If (WinsockError = 10035)  ; No more data to be read
         Return 1
      If WinsockError = 10054 ; Connection closed
         Return NormalClose()
      MsgBox % "Recv() indicated Winsock error " . WinsockError
      ExitApp
   }

   Command := SubStr(ReceivedData, 1, 10)
   ReceivedData := SubStr(ReceivedData, 11)
;^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^

   If (Command = "ARCOMMAND:")
   {
      If InStr(" " . CommandList . " ", " " . ReceivedData . " ")
      {
         If NOT InStr(" " . RunningCommands . " ", " " . ReceivedData . " ")
         {
            RunningCommands .= ReceivedData . " "
            If IsLabel(ReceivedData) ;Should be redundant, but just in case.
               GoSub %ReceivedData%
            StringReplace, RunningCommands, RunningCommands, %A_Space%%ReceivedData%%A_Space%, %A_Space%
         }
      }
   } else If (Command = "ARESPONSE:")
      ClientResponse := ReceivedData

   Return 1
}

NormalClose()
{
   Global OutgoingSocket, ClientResponse := "DISCONNECT"
   Result := DllCall("Ws2_32\closesocket", "UInt", OutgoingSocket)
   If (Result != 0)
   {
      MsgBox % "CloseSocket() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
      ExitApp
   }
   OutgoingSocket =
   Menu TRAY, Tip, AHK Remote Server`n%A_IPAddress1%
   Menu TRAY, Rename, &Disconnect, No Connection
   Menu TRAY, Disable, No Connection
   Return 1
}

;v v v v v v v v v v v v v v v v v v v
SendData(Socket, Data)
{
   SendRet := DllCall("Ws2_32\send", "UInt", Socket, "Str", Data, "Int", StrLen(Data), "Int", 0)
   If (SendRet = -1)
      MsgBox % "Send() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
   Return SendRet
}

;By Laszlo, used by the password function.
RC4txt2hex(Data,Pass) {
   Format := A_FormatInteger
   SetFormat Integer, Hex
   b := 0, j := 0
   VarSetCapacity(Result,StrLen(Data)*4)
   Loop 256 {
      a := A_Index - 1
      Key%a% := Asc(SubStr(Pass, Mod(a,StrLen(Pass))+1, 1))
      sBox%a% := a
   }
   Loop 256 {
      a := A_Index - 1
      b := b + sBox%a% + Key%a%  & 255
      T := sBox%a%
      sBox%a% := sBox%b%
      sBox%b% := T
   }
   Loop Parse, Data
   {
      i := A_Index & 255
      j := sBox%i% + j  & 255
      k := sBox%i% + sBox%j%  & 255
      Result .= Asc(A_LoopField)^sBox%k%
   }
   Result := RegExReplace(Result, "0x(.)(?=0x|$)", "0$1")
   StringReplace Result, Result, 0x,,All
   SetFormat Integer, %Format%
   Return Result
}

InsertInteger(pInteger, ByRef pDest, pOffset = 0, pSize = 4)
{
   Loop %pSize%  ; Copy each byte in the integer into the structure as raw binary data.
      DllCall("RtlFillMemory", "UInt", &pDest + pOffset + A_Index-1, "UInt", 1, "UChar", pInteger >> 8*(A_Index-1) & 0xFF)
}

GuiClose:
ExitApp

DoExit:
TrayExit:
DllCall("Ws2_32\WSACleanup")
ExitApp

TrayEdit:
Edit
Return

TrayReload:
Reload
Return

;^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^

TrayCopy:
ClipBoard := CommandList
Return

TrayDisconnect:
NormalClose()
Return

; ---------------------------------------------------------------------------
; Here are some functions you can use to communicate with the client script.

ARMessage(Text) ;Standard message box.
{
   Global OutgoingSocket
   SendData(OutgoingSocket, "ARMESSAGE:" . Text)
}


ARShowText(Text) ;Shows text in a copyable box, for longer test.
{
   Global OutgoingSocket
   SendData(OutgoingSocket, "ARSHOWTXT:" . Text)
}

ARYesNo(Text) ;Returns 1 (true) for yes.
{
   Global OutgoingSocket, ClientResponse =
   SendData(OutgoingSocket, "ARYESORNO:" . Text)
   Loop
   {
      Sleep 50
      If (ClientResponse == "DISCONNECT")
         Exit
      Else If (ClientResponse != "")
         Return (ClientResponse == "YES")
   }
}

ARInput(Text) ;Returns CANCEL if response is blank or dialog is canceled.
{
   Global OutgoingSocket, ClientResponse =
   SendData(OutgoingSocket, "ARGETINFO:" . Text)
   Loop
   {
      Sleep 50
      If (ClientResponse == "DISCONNECT")
         Exit
      Else If (ClientResponse != "")
         Return ClientResponse
   }
}

ARPassword(Pass) ;Asks for a password .
{                ;Returns 1 (true) for success. If ErrorLevel is 1, it was canceled.
   Global OutgoingSocket, ClientResponse =
   Loop 10
   {
      Random Rand, 1, 255
      Challenge .= Chr(Rand)
   }
   SendData(OutgoingSocket, "ARPASWORD:" . Challenge)
   Loop
   {
      Sleep 50
      If (ClientResponse == "DISCONNECT")
         Exit
      Else If (ClientResponse != "")
      {
         If (ClientResponse = "CANCEL")
         {
            ErrorLevel := 1
            Return 0
         }
         ErrorLevel := 0
         Return (ClientResponse = RC4txt2hex("OPENSESAME", Pass . Challenge))
      }
   }
}

ARMenu(Items) ;Items format: Item1|Item2|Item3, || makes a separator.
{             ;Returns item postion (counting separators) or 0 if canceled.
   Global OutgoingSocket, ClientResponse =
   SendData(OutgoingSocket, "ARPOPMENU:" . Items)
   Loop
   {
      Sleep 50
      If (ClientResponse == "DISCONNECT")
         Exit
      Else If (ClientResponse != "")
         Return ClientResponse
   }
}

; ==========Begin Custom Labels========== (Do not delete this line.)
; Put a comment after a label to prevent it from being a command.

Close_Server:
If ARYesNo("Are you sure?")
   ExitApp
Return

Restart_Server:
Reload
Return

Sound:
SoundGet VolLevel
SoundGet IsMute,, MUTE
SoundInfo := "Vol:" . Round(VolLevel) . "%   Mute:" . IsMute
Result := ARMenu("Volume Up|Volume Down||Mute|Un-Mute||" . SoundInfo)
If (Result = 1)
   SoundSet +10
Else If (Result = 2)
   SoundSet -10
Else If (Result = 4)
   SoundSet 1,, MUTE
Else If (Result = 5)
   SoundSet 0,, MUTE
Return

View_Server_Code:
If A_IsCompiled ;The self-reading trick won't work for compiled scripts.
   ARMessage("Sorry, you can't. It's compiled. ")
Else
{
   FileRead Code, %A_ScriptFullPath%
   Code := RegExReplace(Code, "`as).*\R(?=.*?===" . "Begin Custom Labels" . "===)")
   Code := RegExReplace(Code, "i)(ARPassword)\(.*?\)", "$1(""*******"")")
   ARShowText(Code)
   VarSetCapacity(Code, 0)
}
Return

Ultra_Basic_Chat:
Result := ARInput("Send message:")
Loop
{
   If (Result == "CANCEL")
      Break
   InputBox Result, AHK Remote Server, %Result%,,, 130
   If ErrorLevel
      Break
   Result := ARInput(Result)
}
Return

Shutdown_Computer: ;Change the password below, than remove this comment to enable.
If ARPassword("swordfish")
{
   MsgBox 49, AHK Remote Server, AHK Remote Client requested shutdown. Permit?, 30
   IfMsgBox OK
      Shutdown 12
   Else
      ARMessage("Shutdown aborted by remote user.")
}
Else
   ARMessage("Permission Denied.")
Return

Notice that the last label has a comment after it, this prevents it from becoming a command that the client can use until you remove it. You can do the same thing if you add labels for other purposes, such as like a timer.

On a related note, I made some functions for interacting with the client in basic ways.
  • ARMessage(Text) - Client displays Text in Message Box.
  • ARShowText(Text) - Client displays Text in a copyable text box.
  • ARYesNo(Text) - Client displays Text in Yes/No Message Box. Returns True for Yes.
  • ARInput(Text) - Client displays an Input Box with Text as the prompt. Returns the entered text.
  • ARPassword(Pass) - Client prompts the user for a password and sends it back (encrypted). Returns True if it matches Pass.
  • ARMenu(Items) - Client displays pop-up menu of Items. Returns selected item position.
All of them are demonstrated in the sample commands I included.

These scripts are much more sparsely commented than the sample I mentioned, so if you're trying to learn how to do something similar you're probably better of with that. In case you wondered about the v v v and ^ ^ ^ comments, they indicate that the part in between is the same in both scripts.

I think this script is more suitable for use with a computer across the room than across the world but it does work over the internet as well as a LAN. Comments, suggestions, and bug reports are welcome as always.

Incidentally I found in one case the pre-test with ping failed even though the client was able to connect, probably due to firewall rules, so keep in mind that you can turn the pre-test off by setting TestTimout to blank or 0.


Last edited by ManaUser on September 13th, 2008, 8:07 pm, edited 3 times in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 20th, 2008, 6:51 am 
Offline
User avatar

Joined: August 30th, 2005, 8:43 pm
Posts: 8666
Location: Salem, MA
very cool. I will have to test this later.

Actually, I just need a button to restart my ssh server... this could do it.

_________________
Image
(Common Answers) - New Tutorials Forum - Humongous FAQ


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 21st, 2008, 12:54 am 
Offline

Joined: February 10th, 2007, 5:18 am
Posts: 92
I haven't tried it, but it looks like a great idea


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 21st, 2008, 3:58 am 
Offline

Joined: May 24th, 2007, 3:45 am
Posts: 1121
Fixed security weakness, kind of. I changed the View Server Code command to edit out the password for the ARPassword function. But needless to say, if you have anything sensitive in your script you should probably remove View Server Code completely, all of those commands were really just examples anyway.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 13th, 2008, 4:26 am 
Offline

Joined: May 24th, 2007, 3:45 am
Posts: 1121
I added a new function, ARMenu. It displays a pop-up menu with whatever items you want and returns the position of the selected item. Also, I had a chance to test this over the Internet, and it does indeed work as expected.


Report this post
Top
 Profile  
Reply with quote  
 Post subject: cool
PostPosted: April 12th, 2008, 9:20 am 
Offline

Joined: April 30th, 2006, 6:23 pm
Posts: 358
Location: Shigle Springs
I think this is wonderful and opens many doors to help people or make powerful programs.

I work with a remote deskstop type of program to help my clients. I chose a program, http://www.gidsoftware.com/remotehelpdesk.htm that does a connection from the client to my server because going out through a firewall is much easier than going in through a firewall - nat.. (port forwarding and opening ports is a pain, especially when you are helping a typical end user) :shock:

Does this go out through a firewall to "my" server?

_________________
CPULOCK.com
virusSWAT.com
Computer Repair Computer Service.com
911PCFIX.com


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: April 12th, 2008, 9:33 am 
Offline

Joined: April 30th, 2006, 6:23 pm
Posts: 358
Location: Shigle Springs
also, looking at the code, not by testing, so i hope i am right, ,,,,,, it looks like only one client at a time can connect to the server.

if so, may i sugjest to start at 820 and that once a client connects, a new thread would start with a listening port 82%A_index% # and an ini type file be written on the server so the next client will know what port to try to connect to.

_________________
CPULOCK.com
virusSWAT.com
Computer Repair Computer Service.com
911PCFIX.com


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: September 13th, 2008, 8:15 pm 
Offline

Joined: May 24th, 2007, 3:45 am
Posts: 1121
Update! The main change is that it now takes any kind of address ping understands, instead of only IP. This includes domain names, but also Windows network names, which is pretty handy.

DeWild1 wrote:
also, looking at the code, not by testing, so i hope i am right, ,,,,,, it looks like only one client at a time can connect to the server.

if so, may i sugjest to start at 820 and that once a client connects, a new thread would start with a listening port 82%A_index% # and an ini type file be written on the server so the next client will know what port to try to connect to.

Currently what happens is it boots off the first client when a second one connects. That would be unacceptable for some applications, but I think it's fine for this since you'd normally just be sending quick commands.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: September 14th, 2008, 7:52 pm 
Offline

Joined: September 12th, 2008, 10:48 pm
Posts: 8
why dont you use this function instead?

found this on derRaphael's winsock2 preview code

Code:
/*
 This code based originally upon an example by DarviK
    http://www.autohotkey.com/forum/topic8871.html
 and on the modifcations by Tasman
    http://www.autohotkey.com/forum/viewtopic.php?t=9937
*/
; Resolves canonical domainname to IP
__WSA_GetHostByName(url)
{
    Global __WSA_ErrMsg
    ; gethostbyname returns information about a domainname into a Hostent Structure
    ; http://msdn.microsoft.com/en-us/library/ms738524(VS.85).aspx
    IP := ""
    if ((PtrHostent:=DllCall("Ws2_32\gethostbyname","str",url)) != 0) {
        Loop, 1 ; 3 is max No of retrieved addresses
            If (PtrTmpIP := NumGet(NumGet(PtrHostent+12)+(offset:=(A_Index-1)*4),offset)) {
                IP := (IP) ? IP "|" : ""
                Loop, 4 ; Read our IP address
                    IP .= NumGet(PtrTmpIP+offset,(A_Index-1 ),"UChar") "."
                IP := SubStr(IP,1,-1)
            } else ; No more IPs left
                Break
        result := IP
    } else {
        __WSA_ErrMsg .= "Ws2_32\gethostbyname failed`n "
        result := -1
    }
    return result
}


cheers,

_________________
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: September 14th, 2008, 10:39 pm 
Offline

Joined: May 24th, 2007, 3:45 am
Posts: 1121
Hmm looks promising, definitely a more elegant. The main reason I used ping, is that I was already using it to pre-test for a valid address. No doubt there are more elegant ways to do that too.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: November 4th, 2008, 8:20 pm 
I cant get it to work it says : that some commands are invalid :s


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: April 10th, 2009, 4:31 am 
Offline

Joined: April 8th, 2009, 11:33 am
Posts: 13
thanks ManaUser I've turned it into this...

http://www.autohotkey.com/forum/viewtopic.php?t=42967


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: April 15th, 2009, 1:28 am 
Offline

Joined: May 24th, 2007, 3:45 am
Posts: 1121
Hey, glad you found it useful.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: June 20th, 2009, 8:50 pm 
Offline

Joined: March 27th, 2009, 12:46 pm
Posts: 76
Location: Dublin, IE
Is there anyway to use the client with a windows proxy username and password?

_________________
My Scripts


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 30th, 2009, 5:42 pm 
how could i change it i mean like what the button says, im still really new to ahk and programing iv dabbled into batch abit but i never understood puting words in the boxes


Report this post
Top
  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 25 posts ]  Go to page 1, 2  Next

All times are UTC [ DST ]


Who is online

Users browsing this forum: Google Feedfetcher, oldbrother and 16 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group