Jump to content


Photo

Rename PuTTY Window Title - Permanently


  • Please log in to reply
12 replies to this topic

#1 ninix

ninix
  • Members
  • 17 posts

Posted 28 April 2012 - 03:14 PM

Hi,

I use GNS3 for training and PuTTY as telnet client to devices console port on localhost.
Problem is that all PuTTY windows are named 127.0.0.1 :(
So, I need to dynamically rename each of them with devices hostname...

I use this script which works great, but PuTTY is changing back its Window Title after the window is resized or minimized :x

I don't want to use the script to change that Title every 1 second and to be forced to have in background running one AutoHotKey script (compiled version) for each PuTTY window (memory inefficiency/CPU usage)
There is a way to change PuTTY Title in Linux with a command like this, but I have no idea how to push this as coming from the telnet session and not as a user input (with ControlSend)

Also I want to extract PuTTY text from that window and to match it against a reg-ex REGEX = (%NAME%|ciscoasa|pixfirewall)[#>\(]|Password:|Username:|login:
So this script will send a enter (ControlSend {ENTER}) every second, check again the PuTTY output and send again until the Router/ASA/Pix prompt is shown (In idle state eats one CPU core - Dynamips only)

The rename problem...
;From Linux Shell
echo -e "\033]0; TITLE \007\c"

;This is what PuTTY receive from a Telnet/SSH session as a remote window title changing‎ command
NewTitle := Chr(027) "]1; TITLE " Chr(007) Chr(027) "[1;" Chr(13)

;This is what I tried, but definitely not working ;))
ControlSend,, %NewTitle%, ahk_pid %NewPID%

;And also this in not working to extract window content TEXT
If (!DllCall("AttachConsole", "uint", NewPID))
Partial PuTTY script...
Loop, %0%
	{
	 If (A_Index == 1)
		{
		 HOST := %A_Index%
		}
	 Else If (A_Index == 2)
		{
		 PORT := %A_Index%
		}
	 Else If (A_Index == 3)
		{
		 NAME := %A_Index%
		}

Run, putty.exe -telnet %HOST% %PORT% ,,, NewPID

WinWait ahk_pid %NewPID%
	{
	 WinSetTitle, ahk_pid %NewPID%,, %NAME% - Console Port - [%HOST%:%PORT%]
	}
This is the full script I'm using:
TITLE = Telnet Wrapper Script For GNS3 - by N!NiX - 27/Apr/2012
 ARGS=%0%

 If (ARGS == 0)
	{
	 MsgBox ,, %TITLE%, 
		( LTrim
			Script used to open a telnet program to a GNS3 device Console/AUX
			1) It will change the Window Title according to the device hostname.
			2) Also will resize that window as specified in <X_WinSize> <Y_WinSize>
			   Those values are in pixels, recommended 920 420.
			3) After the telnet connectivity is done, it will push some "Enter" keys
			   until the device console from Routers (Dynamips) will show the prompt.
			   This is useful for me because otherwise that router eats one CPU core.
			
			Works great with Telnet, sometimes with Netcat and partial with PuTTY.
			PuTTY is changing its name back after minimizing the window!
			
			Usage:
			console_wrapper.exe "program.exe" `%h `%p `%d <X_WinSize> <Y_WinSize>
			
			GNS3 Ex:
			console_wrapper.exe telnet.exe `%h `%p `%d 920 420
			console_wrapper.exe nc.exe       `%h `%p `%d 920 420
			console_wrapper.exe putty.exe  `%h `%p `%d 920 420
			
			CLI Ex:
			console_wrapper.exe putty.exe  127.0.0.1 2002 R1 920 420
		)
	 ExitApp
	}
 Else If (ARGS != 6)
	{
	 MsgBox ,, %TITLE%, Invalid parameters number - Must be 6!
	 ExitApp
	}

 StringCaseSense   Off
 DetectHiddenText, Off
 SetControlDelay -1
 EXPECT = 0

 Loop, %0%
	{
	      If (A_Index == 1)
		{
		 TOOL := %A_Index%
		}
	 Else If (A_Index == 2)
		{
		 HOST := %A_Index%
		}
	 Else If (A_Index == 3)
		{
		 PORT := %A_Index%
		}
	 Else If (A_Index == 4)
		{
		 NAME := %A_Index%
		}
	 Else If (A_Index == 5)
		{
		 X_WIN := %A_Index%
		}
	 Else If (A_Index == 6)
		{
		 Y_WIN := %A_Index%
		}
	}

 If (InStr(TOOL, "telnet.exe") || InStr(TOOL, "nc.exe"))
	{
	 Run, %comspec% /C %TOOL% %HOST% %PORT%&&ECHO.&&TITLE %NAME% - Console is closed!&&ECHO Telnet connection "%HOST%:%PORT%" to "%NAME%" console port is lost!&&ECHO Press any key to exit...&&PAUSE >NUL ,,, NewPID
	 EXPECT = 1
	}
 Else If (InStr(TOOL, "putty.exe"))
	{
 	 Run, %TOOL% -telnet %HOST% %PORT% ,,, NewPID
	}
 Else ;Default mode if another tool is used
	{
	 Run, %TOOL% %HOST% %PORT% ,,, NewPID
	}

WinWait ahk_pid %NewPID%
	{
	 If (EXPECT)
		{
		 REGEX = (%NAME%|ciscoasa|pixfirewall)[#>\(]|Password:|Username:|login:|Telnet connection.*Press any key to exit

	 	 ConWinWidth  = 32  ;Maximum router hostname length + # + 1 (CMD line length)
		 ConWinHeight = 100 ;How many lines to read from CMD output

	 	 WinSetTitle, ahk_pid %NewPID%,, %NAME% - Console Port - [%HOST%:%PORT%]
		 WinGetPos, X_Pos, Y_Pos,,, ahk_pid %NewPID%
		 WinMove, ahk_pid %NewPID%,, X_Pos+(mod(PORT, 10)*50)-250, Y_Pos+(mod(PORT, 10)*45)-200, X_WIN, Y_WIN

		 AttachConsole(NewPID)
		 Sleep, 500

		 Text := GetConsoleText(100, 1)
 		 If (!RegExMatch(Text, " Dynamips "))
			{
			 ControlSend,, `r`n, ahk_pid %NewPID%
			 ExitApp ;Manage output to Dynamips only - Until I find a way to do it for Qemu/Pemu
			}
		 If (RegExMatch(Text, " AUX port ") > 1)
			{
			 WinSetTitle, ahk_pid %NewPID%,, %NAME% - AUX Port - [%HOST%:%PORT%]
			}

		 Loop, 45 ;After 45 seconds give up
			{
			 If (RegExMatch(GetConsoleText(ConWinWidth, ConWinHeight), REGEX) > 1)
				{
				 DllCall("FreeConsole")
				 ExitApp
				}
			 Else
				{
				 ControlSend,, `r, ahk_pid %NewPID%
				 Sleep, 1000
				}
			}
		 MsgBox ,, %TITLE%, Console port to device "%NAME%" is not responding!`nSometimes it can be unlocked by opening a bunch of consoles (~3 for Dynamips)
		 ExitApp
		}
	 Else
		{
		 WinMove, ahk_pid %NewPID%,,,, X_WIN, Y_WIN
	 	 WinSetTitle, ahk_pid %NewPID%,, %NAME% - Console Port - [%HOST%:%PORT%]
 		 ControlSend,, `r`n`r`n, ahk_pid %NewPID%
		}
	}

GetConsoleText(ConWinWidth, ConWinHeight)
	{
	 global hConOut

	 VarSetCapacity(info, 24, 0)
	 If (!DllCall("GetConsoleScreenBufferInfo","uint",hConOut,"uint",&info))
		{
		 MsgBox ,, %TITLE%, GetConsoleScreenBufferInfo failed - error %A_LastError%.
		 ExitApp
		}

	 VarSetCapacity(buf, ConWinWidth*ConWinHeight*4, 0)
	 If (!DllCall("ReadConsoleOutput","uint",hConOut,"uint",&buf,"uint",ConWinWidth|ConWinHeight<<16,"uint",0,"uint",&info+10))
		{
		 MsgBox ,, %TITLE%, ReadConsoleOutput failed - error %A_LastError%.
		 ExitApp
		}

	 VarSetCapacity(text, ConWinWidth*ConWinHeight)
	 Loop % ConWinWidth*ConWinHeight
		{
		 text .= Chr(NumGet(buf, 4*(A_Index-1), "Char"))
		}

	 Return text
	}

AttachConsole(pid)
	{
	 global hConOut

	 If (!DllCall("AttachConsole", "uint", pid))
		{
		 MsgBox ,, %TITLE%, AttachConsole failed - error %A_LastError%.
		 ExitApp
		}

	 hConOut:=DllCall("CreateFile","str","CONOUT$","uint",0xC0000000,"uint",7,"uint",0,"uint",3,"uint",0,"uint",0)
	 If (hConOut = -1)
		{
		 MsgBox ,, %TITLE%, CreateFile failed - error %A_LastError%.
		 ExitApp
		}
	}


#2 JSLover

JSLover
  • Members
  • 920 posts

Posted 28 April 2012 - 09:19 PM

Problem is that all PuTTY windows are named 127.0.0.1 :(

...there is a setting for that. PuTTY -> Window -> Behavior -> Window title

I don't want to use the script to change that Title every 1 second...

...I agree, a timer, like this, is kinda a "bad fix".

...and to be forced to have in background running one AutoHotKey script (compiled version) for each PuTTY window...

...you should not need separate scripts for this, you should be able to write one script to manage all the windows...

I'm confused by the rest of your post, do you want to set PuTTY's title, locally, on your computer...or remotely, from the server?

#3 ninix

ninix
  • Members
  • 17 posts

Posted 28 April 2012 - 11:26 PM

Problem is that all PuTTY windows are named 127.0.0.1 :(

...there is a setting for that. PuTTY -> Window -> Behavior -> Window title

Yes there is, but that is just statically for all connections from that moment (by modifying the "Default Settings")
All will have the same title, and my needs are to be dynamically assigned for any new window.
In the same time you are right every PuTTY window has its own settings and maybe that field can be modified somehow with a little AHK magic ;)
Also without showing all clicks and settings windows, there has to be a better way, a PostMessage/NumPut or something :mrgreen:

...and to be forced to have in background running one AutoHotKey script (compiled version) for each PuTTY window...

...you should not need separate scripts for this, you should be able to write one script to manage all the windows...
I'm confused by the rest of your post, do you want to set PuTTY's title, locally, on your computer...or remotely, from the server?

Well, I have no idea how to use only one AHK process active while opening multiple PuTTY windows in the same time, all started from a individual AHK process
OK, confused to me to, So GNS3 use my AHK script to open a PuTTY process every time I press a button "open router console"
Is a chain and AHK is not used as resident or single instance is just reopen for every new command from GNS3.exe

I want to change the title locally to all PuTTY windows, and there I've described that Linux shell is able to change that title remotely (because PuTTY is build that way) by sending a string like this
Chr(027) "]1; TITLE " Chr(007) Chr(027) "[1;" Chr(13) = 1B 5D 31 3B 20 54 49 54 4C 45 20 07 1B 5B 31 3B (HEX containing also the word TITLE)
thru the telnet channel/socket, and I want to ask if is possible to inject that string into the socket as coming form the telnet server, and that will definitely solve the problem.

#4 JSLover

JSLover
  • Members
  • 920 posts

Posted 29 April 2012 - 12:19 AM

Yes there is, but that is just statically for all connections from that moment (by modifying the "Default Settings")

...I didn't mean to edit Default Settings...I really meant to make a PuTTY Saved Session, for each unique title you want...is there alot?...if there's alot (over 5), then I don't recommend this method.

I'm having a hard time figuring out if PuTTY has a -title command line param or not. Fortunatly, I have another idea...create 1 Saved Session, call it anything, but for example "PuTTY Dynamic Title". Set any options you want to apply to all settings, but leave the "Window title" setting alone. Then what? Use AutoHotkey to write in the registry where PuTTY saved the Window title for that Saved Session.

So the idea is...

[*:16dstqs7]Use RegWrite to set the the title for the "PuTTY Dynamic Title" Saved Session
[*:16dstqs7]Run PuTTY, specifying to use that Saved Session, plus any other command line params you need
...the title of that Saved Session would just keep getting overwritten each time you run a new one.

Well, I have no idea how to use only one AHK process active while opening multiple PuTTY windows...

...this is over-simplfiying it, but...

Loop 3 {
	Run, putty
}
...or...

#1::
;// do stuff
Run, putty
return

#2::
;// do other stuff
Run, putty
return


#5 Zaelia

Zaelia
  • Members
  • 706 posts

Posted 29 April 2012 - 07:50 AM

Seems to be not easy, I never used Putty, but as last time on IRC they are some general solution, not elegant and complicated...
Gui, add, text, x-99 y-99, ;null
Gui, +lastfound +resize +0x02000000
Gui, Show, w640 h480, Frame
hParent := WinExist()
Return 

; press F2 for attach current active window with an AHK gui as frame, DO NOT this with background desktop
F2::
DllCall("SetParent", "uint",hChild:=WinExist("A"), "uint",hParent)
WinSet, Style, -0x00cc0000, ahk_id %hChild%
WinMaximize, ahk_id %hChild%
WinGetPos,,, wp, hp, ahk_id %hParent%
WinGetPos,,, wc, hc, ahk_id %hChild%
dx:=wp-wc, dy:=hp-hc
return

GuiSize:
WinGetPos,,, wp, hp, ahk_id %hParent%
WinMove, ahk_id %hChild%,, 0, 0, wp-dx, hp-dy
return

GuiClose:
WinClose, ahk_id %hChild%
While WinExist("ahk_id" hChild)
sleep 1
ExitApp


#6 ninix

ninix
  • Members
  • 17 posts

Posted 29 April 2012 - 08:17 PM

Hi,

Thanks guys!!!
I've made it :D
Not sure if this is the most optimize way to write this tool but works.

I was always looking to the most bizarre ways (inject in a socket, or other crap)
But as JSLover said the regs are Putty's vulnerability, I knew that is storing its stuff in registry, but...... ;)
Zaelia thanks, maybe in the future I'll make the script to open those windows in tabs.

Putty Title
 Loop, % Ceil(1500/(mod(PORT, 20)+1)/4) ;This loop waits maxim ~30 seconds (28.125)
	{
	 ;Read a dummy value, and if is NOT empty/free waits until become or after the loop is timeout
	 RegRead, OutputVar, HKEY_CURRENT_USER, Software\SimonTatham\PuTTY\Sessions\Default`%20Settings, GNS3_AHK_TEST_HOST
	 If (OutputVar != "")
		{
		 Sleep, (mod(PORT, 20)+1)*75 ; QOS for consoles, to be sure that not all are reading the reg at the same time ;)
		}
	 Else
		{
		 Break
		}
	}

 ;Own that dummy value by writing its name (Router Hostname, something unique), change default title, disable remotetitle and start putty.exe
 RegWrite, REG_SZ,    HKEY_CURRENT_USER, Software\SimonTatham\PuTTY\Sessions\Default`%20Settings, GNS3_AHK_TEST_HOST, %NAME%
 RegWrite, REG_SZ,    HKEY_CURRENT_USER, Software\SimonTatham\PuTTY\Sessions\Default`%20Settings, WinTitle,           %NAME% - Console Port - [%HOST%:%PORT%]
 RegWrite, REG_DWORD, HKEY_CURRENT_USER, Software\SimonTatham\PuTTY\Sessions\Default`%20Settings, NoRemoteWinTitle,   1

 Run, Putty.exe -telnet %HOST% %PORT% ,,, NewPID
 
 WinWait ahk_pid %NewPID%
	{
	 RegRead,      OutputVar, HKEY_CURRENT_USER, Software\SimonTatham\PuTTY\Sessions\Default`%20Settings, GNS3_AHK_TEST_HOST
	 If (OutputVar == NAME)
		{
		 ;After that Putty window is active and for sure has its values from registry delete old title and frees dummy value,
		 ;so other AHK precess can begin its turn, without overlaping names between windows by writing/reading all at once
		 ;when multiple console are opened together
		 RegWrite, REG_SZ,    HKEY_CURRENT_USER, Software\SimonTatham\PuTTY\Sessions\Default`%20Settings, GNS3_AHK_TEST_HOST,
		 RegWrite, REG_SZ,    HKEY_CURRENT_USER, Software\SimonTatham\PuTTY\Sessions\Default`%20Settings, WinTitle,
		 RegWrite, REG_DWORD, HKEY_CURRENT_USER, Software\SimonTatham\PuTTY\Sessions\Default`%20Settings, NoRemoteWinTitle, 0
		}

	 WinMove, ahk_pid %NewPID%,,,, X_WIN, Y_WIN
	 ControlSend,, `r, ahk_pid %NewPID%
	}

Full script code
 TITLE = Telnet Wrapper Script For GNS3 - by N!NiX - 27/Apr/2012
 ARGS=%0%

 If (ARGS == 0)
	{
	 MsgBox ,, %TITLE%,
		( LTrim
			Script used to open a telnet program to a GNS3 device Console/AUX
			1) It will change the Window Title according to the device hostname.
			2) Also will resize that window as specified in <X_WinSize> <Y_WinSize>
			   Those values are in pixels, recommended 920 420.
			3) After the telnet connectivity is done, it will push some "Enter" keys
			   until the device console from Routers (Dynamips) will show the prompt.
			   This is useful for me because otherwise that router eats one CPU core.
			
			Works great with Telnet, PuTTY and TeraTerm 3.1.3, other CLI terminals
			might work as well, but only those I've tested.
			
			Usage:
			console_wrapper.exe "PATH\program.exe" `%h `%p `%d <X_WinSize> <Y_WinSize>
			
			GNS3 Ex:
			console_wrapper.exe telnet.exe                    `%h `%p `%d 920 420
			console_wrapper.exe putty.exe                     `%h `%p `%d 920 420
			console_wrapper.exe "X:\..\ttermpro.exe"   `%h `%p `%d 920 420
			
			CLI Ex:
			console_wrapper.exe putty.exe 127.0.0.1 2002 R1 920 420
		)
	 ExitApp
	}
 Else If (ARGS != 6)
	{
	 MsgBox ,, %TITLE%, Invalid parameters number - Must be 6!
	 ExitApp
	}

 StringCaseSense   Off
 DetectHiddenText, Off
 SetControlDelay -1
 MODE = 0

 Loop, %0%
	{
	      If (A_Index == 1)
		{
		 TOOL := %A_Index%
		}
	 Else If (A_Index == 2)
		{
		 HOST := %A_Index%
		}
	 Else If (A_Index == 3)
		{
		 PORT := %A_Index%
		}
	 Else If (A_Index == 4)
		{
		 NAME := %A_Index%
		}
	 Else If (A_Index == 5)
		{
		 X_WIN := %A_Index%
		}
	 Else If (A_Index == 6)
		{
		 Y_WIN := %A_Index%
		}
	}

 If (InStr(TOOL, "telnet.exe"))
	{
	 Run, %comspec% /C %TOOL% %HOST% %PORT%&&ECHO.&&TITLE %NAME% - Console is closed!&&ECHO Telnet connection "%HOST%:%PORT%" to "%NAME%" console port is lost!&&ECHO Press any key to exit...&&PAUSE >NUL ,,, NewPID
	 MODE = 1
	}
 Else If (InStr(TOOL, "putty.exe")) ;PuTTY sucks it is changing its Window Title back when is minimized or resized, so regs tricks are used!
	{
	 Loop, % Ceil(1500/(mod(PORT, 20)+1)/4) ;This loop waits maxim ~30 seconds (28.125)
		{
		 RegRead, OutputVar, HKEY_CURRENT_USER, Software\SimonTatham\PuTTY\Sessions\Default`%20Settings, GNS3_AHK_TEST_HOST
		 If (OutputVar != "")
			{
			 Sleep, (mod(PORT, 20)+1)*75 ; QOS for consoles, to be sure that not all are reading the reg at the same time ;)
			}
		 Else
			{
			 Break
			}
		}

	 RegWrite, REG_SZ,    HKEY_CURRENT_USER, Software\SimonTatham\PuTTY\Sessions\Default`%20Settings, GNS3_AHK_TEST_HOST, %NAME%
	 RegWrite, REG_SZ,    HKEY_CURRENT_USER, Software\SimonTatham\PuTTY\Sessions\Default`%20Settings, WinTitle,           %NAME% - Console Port - [%HOST%:%PORT%]
	 RegWrite, REG_DWORD, HKEY_CURRENT_USER, Software\SimonTatham\PuTTY\Sessions\Default`%20Settings, NoRemoteWinTitle,   1

 	 Run, %TOOL% -telnet %HOST% %PORT% ,,, NewPID
	 MODE = 2
	}
 Else If (InStr(TOOL, "ttermpro.exe"))
	{
	 Run, %TOOL% /T /W="%NAME% - Console Port - [%HOST%:%PORT%]" %HOST%:%PORT% ,,, NewPID
	}
 Else ;Default mode if another tool is used
	{
	 Run, %TOOL% %HOST% %PORT% ,,, NewPID
	}

WinWait ahk_pid %NewPID%
	{
	 If (MODE == 1)
		{
		 REGEX = (%NAME%|ciscoasa|pixfirewall)[#>\(]|Password:|Username:|login:|Telnet connection.*Press any key to exit

	 	 ConWinWidth  = 32  ;Maximum router hostname length + # + 1 (CMD line length)
		 ConWinHeight = 100 ;How many lines to read from CMD output

		 WinGetPos, X_Pos, Y_Pos,,, ahk_pid %NewPID%
		 WinMove, ahk_pid %NewPID%,, X_Pos+(mod(PORT, 10)*50)-250, Y_Pos+(mod(PORT, 10)*45)-200, X_WIN, Y_WIN

		 Loop ; waits until telnet is started (telnet will change title to 127.0.0.1/localhost)...
			{
			 Sleep, 100
			 WinGetTitle, CMDWinTitle, A
			 If (InStr(CMDWinTitle, HOST))
				{
				 WinSetTitle, ahk_pid %NewPID%,, %NAME% - Console Port - [%HOST%:%PORT%]
				 Break
				}
			}

		 AttachConsole(NewPID)
		 Text := GetConsoleText(100, 1)
 		 If (!RegExMatch(Text, " Dynamips "))
			{
			 ControlSend,, `r, ahk_pid %NewPID%
			 ExitApp ;Manage output to Dynamips only - Until I find a way to do it for Qemu/Pemu (It depends for JunOS/IDS/Qemu Host)
			}
		 If (RegExMatch(Text, " AUX port ") > 1)
			{
			 WinSetTitle, ahk_pid %NewPID%,, %NAME% - AUX Port - [%HOST%:%PORT%]
			}

		 Loop, 45 ;After 45 seconds give up
			{
			 If (RegExMatch(GetConsoleText(ConWinWidth, ConWinHeight), REGEX) > 1)
				{
				 DllCall("FreeConsole")
				 ExitApp
				}
			 Else
				{
				 ControlSend,, `r, ahk_pid %NewPID%
				 Sleep, 1000
				}
			}
		 MsgBox ,, %TITLE%, Console port to device "%NAME%" is not responding!`nSometimes it can be unlocked by opening a bunch of consoles (~3 for Dynamips)
		 ExitApp
		}
	 Else If (MODE == 2)
		{
 		 RegRead,      OutputVar, HKEY_CURRENT_USER, Software\SimonTatham\PuTTY\Sessions\Default`%20Settings, GNS3_AHK_TEST_HOST
		 If (OutputVar == NAME)
			{
			 RegWrite, REG_SZ,    HKEY_CURRENT_USER, Software\SimonTatham\PuTTY\Sessions\Default`%20Settings, GNS3_AHK_TEST_HOST,
			 RegWrite, REG_SZ,    HKEY_CURRENT_USER, Software\SimonTatham\PuTTY\Sessions\Default`%20Settings, WinTitle,
			 RegWrite, REG_DWORD, HKEY_CURRENT_USER, Software\SimonTatham\PuTTY\Sessions\Default`%20Settings, NoRemoteWinTitle, 0
			}

		 WinMove, ahk_pid %NewPID%,,,, X_WIN, Y_WIN
 		 ControlSend,, `r, ahk_pid %NewPID%
		}
	 Else
		{
		 WinMove,     ahk_pid %NewPID%,,,, X_WIN, Y_WIN
	 	 WinSetTitle, ahk_pid %NewPID%,, %NAME% - Console Port - [%HOST%:%PORT%]
 		 ControlSend,, `r, ahk_pid %NewPID%
		}
	}

GetConsoleText(ConWinWidth, ConWinHeight)
	{
	 global hConOut

	 VarSetCapacity(info, 24, 0)
	 If (!DllCall("GetConsoleScreenBufferInfo","uint",hConOut,"uint",&info))
		{
		 MsgBox ,, %TITLE%, GetConsoleScreenBufferInfo failed - error %A_LastError%.
		 ExitApp
		}

	 VarSetCapacity(buf, ConWinWidth*ConWinHeight*4, 0)
	 If (!DllCall("ReadConsoleOutput","uint",hConOut,"uint",&buf,"uint",ConWinWidth|ConWinHeight<<16,"uint",0,"uint",&info+10))
		{
		 MsgBox ,, %TITLE%, ReadConsoleOutput failed - error %A_LastError%.
		 ExitApp
		}

	 VarSetCapacity(text, ConWinWidth*ConWinHeight)
	 Loop % ConWinWidth*ConWinHeight
		{
		 text .= Chr(NumGet(buf, 4*(A_Index-1), "Char"))
		}

	 Return text
	}

AttachConsole(pid)
	{
	 global hConOut

	 If (!DllCall("AttachConsole", "uint", pid))
		{
		 MsgBox ,, %TITLE%, AttachConsole failed - error %A_LastError%.
		 ExitApp
		}

	 hConOut:=DllCall("CreateFile","str","CONOUT$","uint",0xC0000000,"uint",7,"uint",0,"uint",3,"uint",0,"uint",0)
	 If (hConOut = -1)
		{
		 MsgBox ,, %TITLE%, CreateFile failed - error %A_LastError%.
		 ExitApp
		}
	}


#7 JSLover

JSLover
  • Members
  • 920 posts

Posted 29 April 2012 - 11:19 PM

If it works, great, but...

[*:2w8id7kk]You don't need to clobber the "Default Settings"...like, I said, you can create a special PuTTY Saved Session & clobber that...
[*:2w8id7kk]Since all your connections are to 127.0.0.1, you can save that in the Saved Session, permanently (not write it with the script)...& then not specify it on the command line either.
[*:2w8id7kk]You have the hard-coded string "Software\SimonTatham\PuTTY\Sessions\Default`%20Settings" 8 times in your full script...you should make that a var & refer to it (but also change the "Default`%20Settings" part to a different Saved Session).
[*:2w8id7kk]The way you use blocks is very odd...you do this...

WinWait ahk_pid %NewPID%
   {
    RegRead,      OutputVar, HKEY_CURRENT_USER, Software\SimonTatham\PuTTY\Sessions\Default`%20Settings, GNS3_AHK_TEST_HOST
    ;//...more...
   }
...WinWait does not care about blocks like that, they do not "direct" the WinWait at those lines.
[*:2w8id7kk]Since you clear the WinTitle value anyway, you could use that as the "flag" instead of GNS3_AHK_TEST_HOST.
[*:2w8id7kk]If you use a custom Saved Session, for this purpose only, you can then stop setting/unsetting NoRemoteWinTitle. Just leave it set (but set it in PuTTY, not in the script).
...my thinking is to make the script simpler & do less...setup a custom/dedicated PuTTY Saved Session, set ALL the defaults you want on it, host = 127.0.0.1, NoRemoteWinTitle=1, set everything that is common to all these connections. Then, in the script, ONLY set/unset the things that are different for each connection, like WinTitle/Port. I'm assuming Port is different each time?...if not, set it in the custom Saved Session, not in the script.

One last comment & I know this will start a war (sorry), but your indentation style really messes with my head...I just can't read it...

If (ARGS == 0)
  {
   MsgBox example
  }
...the whole script would be more readable, for me, if indented like this...

if (ARGS == 0) {
	MsgBox example
}
...plus not using blocks when they actually don't serve a purpose.

#8 ninix

ninix
  • Members
  • 17 posts

Posted 29 April 2012 - 11:57 PM

Hi JSLover ;)

Ok, I come from JavaScript world and that is my style, as editor I use Notepad++ and is shows great there!
I've try to create a new PuTTY profile, but the crazy thing is that PuTTY will use only what is write in that profile called "ProfileX" and the rest of settings will get from its base defaults (hard-coded in putty) and not from "Default Profile", and in "Default Profile" I've change a lot from its really default stuff (colors, disable bell, etc) and by creating a custom profile I have to manually configure it with all options form the "Default Profile" (OK, just once!)

Since you clear the WinTitle value anyway, you could use that as the "flag" instead of GNS3_AHK_TEST_HOST.

You are right, I also want to optimize it to do less cycles and as efficient as possible.
I will remove GNS3_AHK_TEST_HOST and only check if WinTitle is empty or not, in the same time I need NoRemoteWinTitle back to '0' after using GNS3, because I also use PuTTY with Linux servers and there I need that option.
IP/Port is dynamically assigned and is just passed to PuTTY command line not stored in registry.

One last comment & I know this will start a war (sorry), but your indentation style really messes with my head...I just can't read it...

No problem I'm calm :D and new to AHK domain, but I hate VBScript style and as you said I just can't read it

In the mean time I've created this code to check if File TOOL exist (This is a program file *.exe)
So I know how to check is a executable (.exe,.dll,.bat,etc) exists in system PATH with CMD, but not with AHK
And I don't like this part with saving the output from a external command to a file (HDD) and than read/delete that file.
 IfNotExist, %TOOL%
	{
	 TEMP_FILE=%TEMP%\AHK_Temp1.txt
	 RunWait, %COMSPEC% /C @FOR /F `%G IN ("%TOOL%") DO @ECHO `%~dp$PATH:G > %TEMP_FILE%,, Hide
	 FileReadLine, CMD_OUTPUT, %TEMP_FILE%, 1
	 FileDelete, %TEMP_FILE%

	 If (InStr(CMD_OUTPUT, "ECHO is"))
		{
		 MsgBox ,, %TITLE%, Invalid parameter for telnet program!`nFile "%TOOL%" does not exist!
		 ExitApp
		}
	}


#9 JSLover

JSLover
  • Members
  • 920 posts

Posted 30 April 2012 - 02:19 AM

Ok, I come from JavaScript world...

...I do to, I love JavaScript! (but I use the my same style there too)

...and by creating a custom profile I have to manually configure it with all options form the "Default Profile"

...no!...wait, there's a trick!...open PuTTY, select the "Default Profile" (called "Default Settings"), press Load, change the profile name, press Save...I believe that is a way to copy settings from one profile to another.

...in the same time I need NoRemoteWinTitle back to '0' after using GNS3

...if you get multiple profiles working, this won't be a problem anymore.

...I hate VBScript style...

...I'm not sure about "VBScript style", I do hate VBScript, tho. Love JavaScript, Hate VBScript. Love OTB style, Hate anything else.

#10 ninix

ninix
  • Members
  • 17 posts

Posted 30 April 2012 - 12:46 PM

Ok, I come from JavaScript world...

...I do to, I love JavaScript! (but I use the my same style there too)

After creating some JS code I go to JSLint and it really hurt the feelings.
So I like to use {} everywhere a if,for,while,etc is involved, and also I like to do a enter before '{' so when I click on that Notepad++ will highlight all the way down to the corresponding '}', this is more easy for me to read

...and by creating a custom profile I have to manually configure it with all options form the "Default Profile"

...no!...wait, there's a trick!...open PuTTY, select the "Default Profile" (called "Default Settings"), press Load, change the profile name, press Save...I believe that is a way to copy settings from one profile to another.

Thanks, I know that, but the drawback of using a special profile for this script and not use the "default profile" is that I use this script in multiple computers (portable version) and I have to reconfigure that PuTTY everywhere, so I like to be as simple as possible when a new PC is involved. Anyway my coding motto is that I work one entire day to create a script that does everything for me rather than do it my self all the time. It becomes frustrating for me doing same deal all the time, probably that why I start to use scripts (long live the scripts ;) )

Seems that AHK doesn't know about the switch statement so I'm forced to use if,else if,else statements
I saw that others are using Labels, but is works fine like this to...

Last version of code
 StringCaseSense   Off
 DetectHiddenText, Off
 SetControlDelay -1
 MODE      = Default
 BOX_Title = Telnet Wrapper Script For GNS3 - by N!NiX - 30/Apr/2012
 PuTTY_REG = Software\SimonTatham\PuTTY\Sessions\Default`%20Settings
 TEMP_FILE = %TEMP%\AHK_Temp1.txt
 ARGS      = %0%
 
 If (ARGS == 0)
	{
	 MsgBox ,, %BOX_Title%,
		( LTrim
			Script used to open a telnet program to a GNS3 device Console/AUX
			1) It will change the Window Title according to the device hostname.
			2) Also will resize that window as specified in <X_WinSize> <Y_WinSize>
			   Those values are in pixels, recommended 920 420.
			3) After the telnet connectivity is done, it will push some "Enter" keys
			   until the device console from Routers (Dynamips) will show the prompt.
			   This is useful for me because otherwise that router eats one CPU core.
			
			Works great with Telnet, PuTTY, TeraTerm 3.1.3 and SecureCRT 6.7.5
			other CLI/GUI terminals might work as well, but only those I've tested.
			
			Usage:
			console_wrapper.exe "PATH\program.exe" `%h `%p `%d <X_WinSize> <Y_WinSize>
			
			GNS3 Ex:
			console_wrapper.exe telnet.exe                       `%h `%p `%d 920 420
			console_wrapper.exe putty.exe                        `%h `%p `%d 920 420
			console_wrapper.exe "X:\..\ttermpro.exe"     `%h `%p `%d 920 420
			console_wrapper.exe "X:\..\SecureCRT.exe"  `%h `%p `%d 920 420

			CLI Ex:
			console_wrapper.exe putty.exe 127.0.0.1 2002 R1 920 420
		)
	 ExitApp
	}
 Else If (ARGS != 6)
	{
	 UserAlert("Invalid parameters number - Must be 6")
	}

 Loop, %ARGS%
	{
	 If      (A_Index == 1)
		{
		 TOOL := %A_Index%
		}
	 Else If (A_Index == 2)
		{
		 HOST := %A_Index%
		}
	 Else If (A_Index == 3)
		{
		 PORT := %A_Index%
		}
	 Else If (A_Index == 4)
		{
		 NAME := %A_Index%
		}
	 Else If (A_Index == 5)
		{
		 X_WIN := %A_Index%
		}
	 Else If (A_Index == 6)
		{
		 Y_WIN := %A_Index%
		}
	}

 IfNotExist, %TOOL%
	{
	 RunWait, %COMSPEC% /C @FOR /F `%G IN ("%TOOL%") DO @ECHO `%~dp$PATH:G > %TEMP_FILE%,, Hide
	 FileReadLine, CMD_OUTPUT, %TEMP_FILE%, 1
	 FileDelete, %TEMP_FILE%

	 If (InStr(CMD_OUTPUT, "ECHO is"))
		{
		 UserAlert("Invalid parameter for telnet program!`nFile '" TOOL "' does not exist")
		}
	}

 If      ((PORT >= 2000) && (PORT <= 2499))
	{
	 NEW_Title = %NAME% - Console Port - Dynamips - [%HOST%:%PORT%]
	}
 Else If ((PORT >= 2500) && (PORT <= 2999))
	{
	 NEW_Title = %NAME% - AUX Port - Dynamips - [%HOST%:%PORT%]
	}
 Else If ((PORT >= 3000) && (PORT <= 3499))
	{
	 NEW_Title = %NAME% - Console Port - QEMU - [%HOST%:%PORT%]
	}
 Else
	{
	 NEW_Title = %NAME% - Console Port - [%HOST%:%PORT%]
	}

 If (InStr(TOOL, "telnet.exe"))
	{
	 Run, %COMSPEC% /C %TOOL% %HOST% %PORT%&&ECHO.&&TITLE %NAME% - Console is unavailable!&&ECHO Telnet connection "%HOST%:%PORT%" to "%NAME%" Console/AUX port is lost!&&ECHO Press any key to exit...&&PAUSE >NUL ,,, NewPID
	 MODE = CMD
	}
 Else If (InStr(TOOL, "putty.exe")) ;PuTTY sucks it is changing its Window Title back when is minimized or resized, so regs tricks are used!
	{
	 Loop, % Ceil(1500/(mod(PORT, 20)+1)/4) ;This loop waits maxim ~30 seconds (28.125)
		{
		 ;Read the title value, and if is NOT empty/free waits until become or after the loop is timeout
		 RegRead, OutputVar, HKCU, %PuTTY_REG%, WinTitle
		 If (OutputVar != "")
			{
			 Sleep, (mod(PORT, 20)+1)*75 ; QOS for consoles, to be sure that not all are reading the reg at the same time ;)
			}
		 Else
			{
			 Break
			}
		}

	 ;Own that WinTitle value by writing its name (NEW_Title style) so other proceses will wait until become free (empty) again, disable remotetitle and start putty.exe
	 RegWrite, REG_SZ,    HKCU, %PuTTY_REG%, WinTitle,         %NEW_Title%
	 RegWrite, REG_DWORD, HKCU, %PuTTY_REG%, NoRemoteWinTitle, 1

 	 Run, %TOOL% -telnet %HOST% %PORT% ,,, NewPID
	 MODE = PuTTY
	}
 Else If (InStr(TOOL, "SecureCRT.exe"))
	{
	 SplitPath, TOOL,, TOOL_DIR
	 VBS_SCRIPT = %TOOL_DIR%\Scripts\GNS3_Script.vbs
	 IfNotExist, %VBS_SCRIPT%
		{
		 FileAppend, ;Create a VBScript in SecureCRT_Path\Scripts
			(
			 #$Language = "VBScript"`n#$Interface = "1.0"

			 crt.Screen.Synchronous = True

			 Sub main
				 'crt.window.caption = crt.arguments(0)
				 crt.Sleep 1000
				 crt.Screen.Send chr(13)
			 End Sub`n
			), %VBS_SCRIPT%
		}

	 Process, Exist, SecureCRT.exe ;SecureCRT create tabs under the same Process PID, so if exist grab the old PID
	 NewPID = %ErrorLevel%
	 CMD_RUN = %TOOL% /NOMENU /NOTOOLBAR /SCRIPT "%VBS_SCRIPT%" /ARG "%NAME%" /TITLEBAR "GNS3 Terminal Manager - SecureCRT" /T /N "%NAME%" /TELNET %HOST% %PORT%
	 If (NewPID == 0)
		{
		 Run, %CMD_RUN% ,,, NewPID
		}
	 Else
		{
		 Run, %CMD_RUN%
		}
	 MODE = SecureCRT
	}
 Else If (InStr(TOOL, "ttermpro.exe"))
	{
	 Run, %TOOL% /T /W="%NEW_Title%" %HOST%:%PORT% ,,, NewPID
	}
 Else ;Default mode if another tool is used
	{
	 Run, %TOOL% %HOST% %PORT% ,,, NewPID
	}

 WinWait ahk_pid %NewPID%

 If (MODE == "CMD") ;CMD windows (Telnet/NC)
	{
	 REGEX = (%NAME%|ciscoasa|pixfirewall)[#>\(]|Password:|Username:|login:|Telnet connection.*Press any key to exit

	 ConWinWidth  = 32  ;Maximum router hostname length + # + 1 (CMD line length)
	 ConWinHeight = 100 ;How many lines to read from CMD output

	 WinGetPos, X_Pos, Y_Pos,,, ahk_pid %NewPID%
	 WinMove, ahk_pid %NewPID%,, X_Pos+(mod(PORT, 10)*50)-250, Y_Pos+(mod(PORT, 10)*45)-200, X_WIN, Y_WIN

	 Loop ; waits until telnet is started (telnet will change title to 127.0.0.1/localhost)...
		{
		 Sleep, 100
		 WinGetTitle, CMDWinTitle, A
		 If (InStr(CMDWinTitle, HOST))
			{
			 WinSetTitle, ahk_pid %NewPID%,, %NEW_Title%
			 Break
			}
		}

	 AttachConsole(NewPID)
	 If (!RegExMatch(GetConsoleText(100, 4), " Dynamips "))
		{
		 ControlSend,, `r, ahk_pid %NewPID%
		 ExitApp ;Manage output to Dynamips only - Until I find a way to do it for Qemu/Pemu (It depends for JunOS/IDS/Qemu Host)
		}

	 Loop, 45 ;After 45 seconds give up
		{
		 If (RegExMatch(GetConsoleText(ConWinWidth, ConWinHeight), REGEX))
			{
			 DllCall("FreeConsole")
			 ExitApp
			}
		 Else
			{
			 ControlSend,, `r, ahk_pid %NewPID%
			 Sleep, 1000
			}
		}
	 UserAlert("Console port to device '" NAME "' is not responding!`nSometimes it can be unlocked by opening a bunch of consoles (~3 for Dynamips)")
	}
 Else If (MODE == "PuTTY")
	{
	 ;After that Putty window is active and for sure has its values from registry delete old title,so other AHK precess can begin them turn,
	 ;without overlaping names between windows by writing/reading all at once when multiple console are opened together
	 RegWrite, REG_SZ,    HKCU, %PuTTY_REG%, WinTitle,
	 RegWrite, REG_DWORD, HKCU, %PuTTY_REG%, NoRemoteWinTitle, 0

	 WinMove, ahk_pid %NewPID%,,,, X_WIN, Y_WIN
	 ControlSend,, `r, ahk_pid %NewPID%
	}
 Else If (MODE == "SecureCRT")
	{
	 WinMove,     ahk_pid %NewPID%,,,, X_WIN, Y_WIN
	 ;ControlSend,, `r, ahk_pid %NewPID% ;I do this from the VBScript is more efficient when opening multiple tabs at once
	}
 Else ;TeraTerm and others
	{
	 WinMove,     ahk_pid %NewPID%,,,, X_WIN, Y_WIN
	 WinSetTitle, ahk_pid %NewPID%,, %NEW_Title%
	 ControlSend,, `r, ahk_pid %NewPID%
	}

 UserAlert(MsgText)
	{
	 global BOX_Title
	 MsgBox, 48, %BOX_Title%, %MsgText% !
	 ExitApp
	}

 GetConsoleText(ConWinWidth, ConWinHeight)
	{
	 global hConOut

	 VarSetCapacity(info, 24, 0)
	 If (!DllCall("GetConsoleScreenBufferInfo","uint",hConOut,"uint",&info))
		{
		 UserAlert("GetConsoleScreenBufferInfo failed - error " A_LastError)
		}

	 VarSetCapacity(buf, ConWinWidth*ConWinHeight*4, 0)
	 If (!DllCall("ReadConsoleOutput","uint",hConOut,"uint",&buf,"uint",ConWinWidth|ConWinHeight<<16,"uint",0,"uint",&info+10))
		{
		 UserAlert("ReadConsoleOutput failed - error " A_LastError)
		}

	 VarSetCapacity(text, ConWinWidth*ConWinHeight)
	 Loop % ConWinWidth*ConWinHeight
		{
		 text .= Chr(NumGet(buf, 4*(A_Index-1), "Char"))
		}

	 Return text
	}

AttachConsole(PID)
	{
	 global hConOut

	 If (!DllCall("AttachConsole", "uint", PID))
		{
		 UserAlert("AttachConsole failed - error " A_LastError)
		}

	 hConOut:=DllCall("CreateFile","str","CONOUT$","uint",0xC0000000,"uint",7,"uint",0,"uint",3,"uint",0,"uint",0)
	 If (hConOut = -1)
		{
		 UserAlert("CreateFile failed - error " A_LastError)
		}
	}


#11 sinkfaze

sinkfaze
  • Moderators
  • 6089 posts

Posted 30 April 2012 - 04:07 PM

Couldn't you use OnMessage to monitor the appropriate messages and change the title only when needed?

#12 JSLover

JSLover
  • Members
  • 920 posts

Posted 01 May 2012 - 03:38 AM

...but the drawback of using a special profile for this script ... is that I use this script in multiple computers (portable version) and I have to reconfigure that PuTTY everywhere...

...in that case, set up the profile once, on one computer, then either export the .reg file & import it on the other computers...or look at the .reg file & create an AutoHotkey script to do the same thing. If that custom PuTTY profile don't exist, have the script create it.

Seems that AHK doesn't know about the switch statement...

...a VERY long time ago, I wrote some functions to simulate the feeling of a switch/case...

Base.ahi
Switch-Case.ahi & Example