#tag Class
Protected Class IdleLogout
Inherits Application
#tag Event
Sub Open()
Dim debugFileName as string
Dim theDate as date
dim mXMLtreeToFollow(-1) as string
dim mPrefKeyFoundData(-1) as string
dim mTempFoundPlistData as string = "" // Local variable to use for gathering plist settings
theDate = new Date
Globals.gAppFolderItem = GetFolderItem("/Users/Shared/", FolderItem.PathTypeShell)
if Globals.gAppFolderItem.Exists = false then
Globals.gAppFolderItem = GetFolderItem("/tmp/", FolderItem.PathTypeShell)
MsgBox "Can't find /Users/Shared! Using /tmp/ for logs"
end
// Set the name of the log
debugFileName = "psuIdleLogout.RUN" + MiscMethods.PadData("0",2,str(theDate.Year),Globals.kLogToFileDisable) _
+ "-" + MiscMethods.PadData("0",2,str(theDate.Month),Globals.kLogToFileDisable) + "-"
debugFileName = debugFileName + MiscMethods.PadData("0",2,str(theDate.Day),Globals.kLogToFileDisable) + _
"-" + MiscMethods.PadData("0",2,str(theDate.Hour),Globals.kLogToFileDisable) + "-"
debugFileName = debugFileName + MiscMethods.PadData("0",2,str(theDate.Minute),Globals.kLogToFileDisable) + _
"-" + MiscMethods.PadData("0",2,str(theDate.Second),Globals.kLogToFileDisable) + ".log"
// Initilize the log, quit if we can't create the log
if not (LogToFile.Initialize(debugFileName,Globals.gAppFolderItem)) then
beep
MsgBox "Error creating run log file! Exiting..."
quit
end if
// Keep only the last 5 logs
if ( LogToFile.DeleteOldLogs(5) ) then
LogToFile("Deleted Old Logs")
end if
// Get App Prefs
Prefs = new TTsSmartPreferences("edu.psu.idlelogout")
// Check for the user to ignore
pIgnoreUser = Prefs.Value("IgnoreUser", "macadmin")
// Check the group to ignore
pIgnoreGroup = Prefs.Value ("IgnoreGroup", "admin")
// How long should we wait before considering the Mac is idle too long?
pComputerIdleAfterNumSeconds = Prefs.Value("ComputerIdleAfterNumSeconds", 600)
// How often should we check to see how long the Mac has been idle?
pIdleLoopDelaySeconds = Prefs.Value("IdleLoopDelaySeconds", 30)
// How long should we wait for the user to respond for More Time or to Log Out?
pWaitForUserPromptSeconds = Prefs.Value("WaitForUserPromptSeconds",90)
// What should we display on the popup window text
pWindowMessage = Prefs.Value("WindowMessage",pWindowMessage)
// Create temp string with new line char
Dim cr As String
cr = EndOfLine.Unix
// Replace \n with new line chars
pWindowMessage = ReplaceAllB(pWindowMessage, "\n", EndOfLine)
// Update Window Message
LogoutWarning.WarningMessage.setString(pWindowMessage)
// What should the Title Be in the Popup Window
pWindowTitle = Prefs.Value("WindowTitle","Idle Logout Alert")
// Update Window Title
LogoutWarning.WarningTitle.setString(pWindowTitle)
// Set Values in the Plist - Probably don't need to touch the disk
'Prefs.Value("IgnoreUser") = pIgnoreUser
'Prefs.Value ("IgnoreGroup") = pIgnoreGroup
'Prefs.Value("ComputerIdleAfterNumSeconds") = pComputerIdleAfterNumSeconds
'Prefs.Value("IdleLoopDelaySeconds") = pIdleLoopDelaySeconds
'Prefs.Value("WaitForUserPromptSeconds") = pWaitForUserPromptSeconds
'Prefs.Value("WindowMessage") = pWindowMessage
'Prefs.Value("WindowTitle") = pWindowTitle
'Prefs.Sync
LogToFile(CurrentMethodName + ": Received user exception = " + str(pIgnoreUser) )
LogToFile(CurrentMethodName + ": Received group exception = " + str(pIgnoreGroup) )
LogToFile(CurrentMethodName + ": Received ComputerIdleAfterNumSeconds = " + str(pComputerIdleAfterNumSeconds) )
LogToFile(CurrentMethodName + ": Received IdleLoopDelaySecond, = " + str(pIdleLoopDelaySeconds) )
LogToFile(CurrentMethodName + ": Received WaitForUserPromptSeconds = " + str(pWaitForUserPromptSeconds) )
// Is this user macadmin?
if ( MiscMethods.CurrentUsername(pIgnoreUser) ) then
// It is macadmin, quit the app
LogToFile("Current user is " + pIgnoreUser + ", quiting app")
quit
else
LogToFile("User is not " + pIgnoreUser + ", continuing")
end if
// Is this user an admin?
if ( MiscMethods.CurrentGroup(pIgnoreGroup) ) then
// It is macadmin, quit the app
LogToFile("Current user is an " + pIgnoreGroup + ", quiting app")
quit
else
LogToFile("User is not an " + pIgnoreGroup + ", continuing")
end if
// Hide window from view at start
LogoutWarning.Hide()
// Start IdleThread
LogToFile(CurrentMethodName + ": Running IdleThread")
// start thread to watch for idle
StartIdleWatch()
// exit app now
LogToFile(CurrentMethodName + ": <---")
End Sub
#tag EndEvent
#tag Method, Flags = &h0
Sub forceLogout()
LogToFile(CurrentMethodName + ": --->")
// Testing mode, use say instead of logout
Dim s As Shell
s=New Shell
dim ShellResults as string
s.Mode = 0
// Log
LogToFile(CurrentMethodName + ": START Killing Apps")
// Graceful quit of apps
LogToFile(CurrentMethodName + ": Quiting all launched from /Applications")
s.Execute("ps axxx -o comm | grep ""/Applications"" | grep -v grep | awk -F'.app' '{print $1"".app""}'")
Dim runningapps as string
runningapps = s.Result
// Create New Array for running apps
Dim appArray() as String
// Place each line in new array
appArray=SPLIT(runningapps,EndOfLine)
// For each app in the array try to graceful quit
For Each appPath as string in appArray
if appPath = "" then
Continue
end
LogToFile("Quiting: " + appPath)
s.Execute("osascript -e 'quit app ""appPath""'")
LogToFile(" Exit Code: " + str(s.ErrorCode))
Next
// kill the apps that are open from /Apps
LogToFile(CurrentMethodName + ": Killing all launched from /Applications")
s.Execute("kill -9 `ps axxx | grep ""/Applications"" | awk '{print $1}'`")
LogToFile(CurrentMethodName + ": App Kill Results: " + s.Result)
// Log out our user with force
LogToFile(CurrentMethodName + ": Tell AppleScript to log it out")
// New method to logout with osascript.
s.Execute("osascript -e 'tell application ""System Events"" to keystroke ""q"" using {command down, shift down, option down}'")
LogToFile(CurrentMethodName + ": LogOut AS Results: " + s.Result)
// Log and quit
LogToFile(CurrentMethodName + ": <---")
End Sub
#tag EndMethod
#tag Method, Flags = &h0
Function IdleSeconds() As Integer
// Set up variables for idle time
// Shell result
Dim mIdleSecs As String
// Shell exit code
Dim merrCode As Integer
// Set up shell
Dim s As Shell
s=New Shell
s.Mode = 0
// Check idle time
//s.Execute code to check idle time from USB input devices
s.Execute "/bin/echo $((`/usr/sbin/ioreg -c IOHIDSystem | /usr/bin/sed -e '/HIDIdleTime/ !{ d' -e 't' -e '}' -e 's/.* = //g' -e 'q'` / 1000000000))"
// Set results to mIdleResult
mIdleSecs = s.Result
// Set error code to mIdleError
merrCode = s.ErrorCode
// Log mIdleResult for debugging
// System.Log(System.LogLevelError, "Method: " + midleSecs)
// LogToFile("mIdleSeconds: " + str(mIdleSecs))
Return val(mIdleSecs)
End Function
#tag EndMethod
#tag Method, Flags = &h0
Function makeFolder(mkdirPath As string) As Boolean
// Set up variables for idle time
// Shell result = mkdirPath
// Shell exit code
Dim merrCode As Integer
// Set up shell
Dim s As Shell
s=New Shell
s.Mode = 0
// Check idle time
//s.Execute code to check idle time from USB input devices
s.Execute "mkdir -p /Users/Shared"
// Set results to mIdleResult
mkdirPath = s.Result
// Set error code to mIdleError
merrCode = s.ErrorCode
// Log mIdleResult for debugging
// System.Log(System.LogLevelError, "Method: " + midleSecs)
// LogToFile("mIdleSeconds: " + str(mIdleSecs))
if mkdirPath = "0" then
return true
else
return false
end
End Function
#tag EndMethod
#tag Method, Flags = &h0
Function RemoteControlCheck() As Boolean
// Set up variables for idle time
Dim stablished as String = "ESTABLISHED"
// Shell result
Dim rccheck As String
// Shell exit code
Dim merrCode As Integer
// Set up shell
Dim s As Shell
s=New Shell
s.Mode = 0
// Check idle time
//s.Execute code to check for connection
s.Execute "/usr/sbin/netstat -n | /usr/bin/grep '.5900'| /usr/bin/awk '{print $6}'"
// Set results to rccheck
// Make the entire returned text uppercase in case Apple ever changes the case to CaMeL CaSe, which would break our code:
rccheck = Uppercase(s.Result)
//LogToFile("rccheck: " + rccheck)
// Set error code to merrCode
merrCode = s.ErrorCode
// LogToFile("rccheck: "+ rccheck)
// LogToFile("stablished: "+ stablished)
If ( InStr( rccheck, stablished ) > 0 ) then
return true
else
//LogToFile("rccheck: false")
return false
End if
// System.Log(System.LogLevelError, "Method: " + midleSecs)
// LogToFile("mIdleSeconds: " + str(mIdleSecs))
End Function
#tag EndMethod
#tag Method, Flags = &h0
Sub StartIdleWatch()
// if the new WatchForIdleThread is not created, do it now
if ( pWatchForIdleThread = nil ) then
// instatiate new thread with enumerated type
pWatchForIdleThread = _
new WatchForIdleThread(Int32(eTaskType.StartIdleWatch ))
// add custom methods for run and finished handlers
AddHandler pWatchForIdleThread.Run, WeakAddressOf Thread_WaitForIdleTime
AddHandler pWatchForIdleThread.Finished, WeakAddressOf Thread_Finished
end if
// Run the thread if it's not already running:
if ( pWatchForIdleThread.State <> Thread.Running ) then
// Hide window during idle watch
LogoutWarning.Hide()
// Set label to default countdown time
LogoutWarning.TimeLabel.setString(str(pWaitForUserPromptSeconds))
// run the new thread
pWatchForIdleThread.Run
end if
End Sub
#tag EndMethod
#tag Method, Flags = &h0
Sub StartUserCountDown()
// if the new WatchForIdleThread is not created, do it now
if ( pIdleCountDownThread = nil ) then
// instatiate new thread with enumerated type
pIdleCountDownThread = _
new WatchForIdleThread(Int32(eTaskType.StartUserCountDown ))
// add custom methods for run and finished handlers
AddHandler pIdleCountDownThread.Run, WeakAddressOf Thread_WaitForUserInput
AddHandler pIdleCountDownThread.Finished, WeakAddressOf Thread_Finished
end if
// Run the thread if it's not already running
if ( pIdleCountDownThread.State <> Thread.Running ) then
// run the new thread
pIdleCountDownThread.Run
end if
End Sub
#tag EndMethod
#tag Method, Flags = &h21
Private Sub Thread_Finished(paramThread as WatchForIdleThread)
LogToFile(CurrentMethodName + ": --->")
// Kill the thread that was used to get here
paramThread.Kill
// Found out which thread just finished
select case Int32 ( paramThread.pTaskType )
// If the StartIdleWatch thread just finished
case int32( eTaskType.StartIdleWatch )
// LogToFile(CurrentMethodName + ": Idle time has expired.")
// Show Login Window
LogoutWarning.Show()
// start logout countdown window
StartUserCountDown()
case int32 ( eTaskType.StartUserCountDown )
// LogToFile(CurrentMethodName + ": No user response from countdown.")
// LogToFile(CurrentMethodName + ": LogoutWarning.pMoreTimeAskedFor = " +str(pMoreTimeAskedFor))
// If the user (or anyone) asked for more time
if (pMoreTimeAskedFor) then
// if the user asks for more time, start the idle watch thread again
// Restart Idle Watch
StartIdleWatch()
else
// if the user ran out of time, start the logout
// kill user logins
forceLogout()
end if
else
end select
End Sub
#tag EndMethod
#tag Method, Flags = &h21
Private Sub Thread_WaitForIdleTime(paramThread as WatchForIdleThread)
// Set up new integer to store idle seconds
Dim mIdleResult As Integer
// get current idle seconds
mIdleResult = IdleSeconds()
// LogToFile(CurrentMethodName + " Idle Seconds: " + str(mIdleResult))
// LogToFile(CurrentMethodName + " waiting for " + str(LogoutWarning.pComputerIdleAfterNumSeconds))
// While our idle result is less than max time
while ( mIdleResult < pComputerIdleAfterNumSeconds )
// Wait pIdleLoopDelaySeconds each loop
App.SleepCurrentThread( pIdleLoopDelaySeconds * 1000 )
// Check idle time:
mIdleResult = IdleSeconds()
// Log our time idle
LogToFile(CurrentMethodName + ": Idle Seconds: " + str(mIdleResult))
wend
// while there is a ARD/VNC session, don't idle out (netstat -n | grep '.5900')
while (RemoteControlCheck() )
// Wait pIdleLoopDelaySeconds each loop
App.SleepCurrentThread( pIdleLoopDelaySeconds * 1000 )
// Log
LogToFile(CurrentMethodName + ": Someone is controlling via ARD/VNC, waiting...")
wend
// When there is not remote control
LogToFile(CurrentMethodName + ": No one is controlling via ARD/VNC, continuing...")
End Sub
#tag EndMethod
#tag Method, Flags = &h21
Private Sub Thread_WaitForUserInput(paramThread as WatchForIdleThread)
LogToFile(CurrentMethodName + ": --->")
// Set how long to wait before logging out user, set from global variable for LogOutDelay
Dim pLogoutDelay as Integer = pWaitForUserPromptSeconds
// While we're waiting for the countdown to finish...
While pLogoutDelay >= 0
// LogToFile(CurrentMethodName + "Time Left: " + str(pLogoutDelay))
// Set global variable to the time left
pCountDownTime = pLogoutDelay
// call updateUI to set countdown label
pIdleCountDownThread.UpdateUI()
// take a second away from the time left
pLogoutDelay = pLogoutDelay - 1
// do nothing for 1 second
App.SleepCurrentThread( 1000 ) // sleep 1 second
Wend
// If we're here, the user didn't cancel or log out manaully
// user did not ask for more time
pMoreTimeAskedFor = false
// Log
LogToFile(CurrentMethodName + ": Time Out for Response. Log User Out...")
// Done here
LogToFile(CurrentMethodName + ": <---")
// Return to Thread_Finished
End Sub
#tag EndMethod
#tag Note, Name = Icon
Application Icon use with CC license:
From http://www.flickr.com/photos/23453447@N02/5107438855/sizes/o/in/photostream/
By zyrquel
http://www.flickr.com/photos/23453447@N02/
#tag EndNote
#tag Note, Name = Tests
New builds should be tested for:
Launching
Hiding Dock Icon
Logging to File
Reading Preferences
Reading Idle Time
Countdown Timer starts when idle time reached
Countdown Window Shows
More Time button resets the clock
Log Out Button quits open apps and logs out
Timer Runs out and Auto-Logs Out
Remove Control Blocks logout
Custom Name
Custom Text
defaults write /Library/Preferences/edu.psu.idlelogout.plist IgnoreUser -string clcclmadmin
defaults write /Library/Preferences/edu.psu.idlelogout.plist IgnoreGroup -string user
defaults write /Library/Preferences/edu.psu.idlelogout.plist ComputerIdleAfterNumSeconds -string 10
defaults write /Library/Preferences/edu.psu.idlelogout.plist IdleLoopDelaySeconds -string 5
defaults write /Library/Preferences/edu.psu.idlelogout.plist WaitForUserPromptSeconds -string 120
defaults write /Library/Preferences/edu.psu.idlelogout.plist WindowTitle -string "Our Idle Logout"
defaults write /Library/Preferences/edu.psu.idlelogout.plist WindowMessage "You're going to be logged out\n\n\nDude\!"
#tag EndNote
#tag Property, Flags = &h0
pAppVersion As String = "2.1"
#tag EndProperty
#tag Property, Flags = &h0
pComputerIdleAfterNumSeconds As Integer = 900
#tag EndProperty
#tag Property, Flags = &h0
pCountDownTime As Integer
#tag EndProperty
#tag Property, Flags = &h0
pDefaultPrefsFileName As String = "edu.psu.its.clc.IdleLogoutSettings.plist"
#tag EndProperty
#tag Property, Flags = &h0
pDefaultPrefsFSPath As String = "/Library/CLMadmin/Config/"
#tag EndProperty
#tag Property, Flags = &h0
pIdleCountDownThread As WatchForIdleThread
#tag EndProperty
#tag Property, Flags = &h0
pIdleLoopDelaySeconds As Integer = 60
#tag EndProperty
#tag Property, Flags = &h0
pIgnoreGroup As String = "admin"
#tag EndProperty
#tag Property, Flags = &h0
pIgnoreUser As String = "clmadmin"
#tag EndProperty
#tag Property, Flags = &h0
pMoreTimeAskedFor As Boolean = true
#tag EndProperty
#tag Property, Flags = &h0
Prefs As TTsSmartPreferences
#tag EndProperty
#tag Property, Flags = &h0
pWaitForUserPromptSeconds As Integer = 90
#tag EndProperty
#tag Property, Flags = &h0
pWatchForIdleThread As WatchForIdleThread
#tag EndProperty
#tag Property, Flags = &h0
pWindowMessage As String = "This Mac is now Idle.\n\nClick the ""More Time"" button to continue using the Mac.\n\nOtherwise, an automatic logout will occur and all unsaved documents will be LOST!"
#tag EndProperty
#tag Property, Flags = &h0
pWindowTitle As String
#tag EndProperty
#tag Constant, Name = kEditClear, Type = String, Dynamic = False, Default = \"&Delete", Scope = Public
#Tag Instance, Platform = Windows, Language = Default, Definition = \"&Delete"
#Tag Instance, Platform = Linux, Language = Default, Definition = \"&Delete"
#tag EndConstant
#tag Constant, Name = kFileQuit, Type = String, Dynamic = False, Default = \"&Quit", Scope = Public
#Tag Instance, Platform = Windows, Language = Default, Definition = \"E&xit"
#tag EndConstant
#tag Constant, Name = kFileQuitShortcut, Type = String, Dynamic = False, Default = \"", Scope = Public
#Tag Instance, Platform = Mac OS, Language = Default, Definition = \"Cmd+Q"
#Tag Instance, Platform = Linux, Language = Default, Definition = \"Ctrl+Q"
#tag EndConstant
#tag Enum, Name = eTaskType, Type = Int32, Flags = &h0
StartIdleWatch
StartUserCountDown
#tag EndEnum
#tag ViewBehavior
#tag ViewProperty
Name="pAppVersion"
Group="Behavior"
InitialValue="1.1"
Type="String"
EditorType="MultiLineEditor"
#tag EndViewProperty
#tag ViewProperty
Name="pComputerIdleAfterNumSeconds"
Group="Behavior"
InitialValue="900"
Type="Integer"
#tag EndViewProperty
#tag ViewProperty
Name="pCountDownTime"
Group="Behavior"
Type="Integer"
#tag EndViewProperty
#tag ViewProperty
Name="pDefaultPrefsFileName"
Group="Behavior"
InitialValue="edu.psu.its.clc.IdleLogoutSettings.plist"
Type="String"
EditorType="MultiLineEditor"
#tag EndViewProperty
#tag ViewProperty
Name="pDefaultPrefsFSPath"
Group="Behavior"
InitialValue="/Library/CLMadmin/Config/"
Type="String"
EditorType="MultiLineEditor"
#tag EndViewProperty
#tag ViewProperty
Name="pIdleLoopDelaySeconds"
Group="Behavior"
InitialValue="60"
Type="Integer"
#tag EndViewProperty
#tag ViewProperty
Name="pIgnoreGroup"
Group="Behavior"
InitialValue="admin"
Type="String"
EditorType="MultiLineEditor"
#tag EndViewProperty
#tag ViewProperty
Name="pIgnoreUser"
Group="Behavior"
InitialValue="macadmin"
Type="String"
EditorType="MultiLineEditor"
#tag EndViewProperty
#tag ViewProperty
Name="pMoreTimeAskedFor"
Group="Behavior"
InitialValue="true"
Type="Boolean"
#tag EndViewProperty
#tag ViewProperty
Name="pWaitForUserPromptSeconds"
Group="Behavior"
InitialValue="90"
Type="Integer"
#tag EndViewProperty
#tag ViewProperty
Name="pWindowMessage"
Group="Behavior"
InitialValue="'This Mac is idle. Click the """"More Time"""" button to continue using the Mac. Otherwise, an automatic logout will occur and all unsaved documents will be LOST!"
Type="String"
#tag EndViewProperty
#tag ViewProperty
Name="pWindowTitle"
Group="Behavior"
Type="String"
#tag EndViewProperty
#tag EndViewBehavior
End Class
#tag EndClass
\ No newline at end of file
#tag Class
Protected Class IdleLogout
Inherits Application
#tag Event
Sub Open()
Dim debugFileName as string
Dim theDate as date
dim mXMLtreeToFollow(-1) as string
dim mPrefKeyFoundData(-1) as string
dim mTempFoundPlistData as string = "" // Local variable to use for gathering plist settings
theDate = new Date
Globals.gAppFolderItem = GetFolderItem("/Users/Shared/", FolderItem.PathTypeShell)
if Globals.gAppFolderItem.Exists = false then
Globals.gAppFolderItem = GetFolderItem("/tmp/", FolderItem.PathTypeShell)
MsgBox "Can't find /Users/Shared! Using /tmp/ for logs"
end
// Set the name of the log
debugFileName = "psuIdleLogout.RUN" + MiscMethods.PadData("0",2,str(theDate.Year),Globals.kLogToFileDisable) _
+ "-" + MiscMethods.PadData("0",2,str(theDate.Month),Globals.kLogToFileDisable) + "-"
debugFileName = debugFileName + MiscMethods.PadData("0",2,str(theDate.Day),Globals.kLogToFileDisable) + _
"-" + MiscMethods.PadData("0",2,str(theDate.Hour),Globals.kLogToFileDisable) + "-"
debugFileName = debugFileName + MiscMethods.PadData("0",2,str(theDate.Minute),Globals.kLogToFileDisable) + _
"-" + MiscMethods.PadData("0",2,str(theDate.Second),Globals.kLogToFileDisable) + ".log"
// Initilize the log, quit if we can't create the log
if not (LogToFile.Initialize(debugFileName,Globals.gAppFolderItem)) then
beep
MsgBox "Error creating run log file! Exiting..."
quit
end if
// Keep only the last 5 logs
if ( LogToFile.DeleteOldLogs(5) ) then
LogToFile("Deleted Old Logs")
end if
// Get App Prefs
Prefs = new TTsSmartPreferences("edu.psu.idlelogout")
// Check for the user to ignore
pIgnoreUser = Prefs.Value("IgnoreUser", "macadmin")
// Check the group to ignore
pIgnoreGroup = Prefs.Value ("IgnoreGroup", "admin")
// How long should we wait before considering the Mac is idle too long?
pComputerIdleAfterNumSeconds = Prefs.Value("ComputerIdleAfterNumSeconds", 600)
// How often should we check to see how long the Mac has been idle?
pIdleLoopDelaySeconds = Prefs.Value("IdleLoopDelaySeconds", 30)
// How long should we wait for the user to respond for More Time or to Log Out?
pWaitForUserPromptSeconds = Prefs.Value("WaitForUserPromptSeconds",90)
// What should we display on the popup window text
pWindowMessage = Prefs.Value("WindowMessage",pWindowMessage)
// Create temp string with new line char
Dim cr As String
cr = EndOfLine.Unix
// Replace \n with new line chars
pWindowMessage = ReplaceAllB(pWindowMessage, "\n", EndOfLine)
// Update Window Message
LogoutWarning.WarningMessage.setString(pWindowMessage)
// What should the Title Be in the Popup Window
pWindowTitle = Prefs.Value("WindowTitle","Idle Logout Alert")
// Update Window Title
LogoutWarning.WarningTitle.setString(pWindowTitle)
// Set Values in the Plist - Probably don't need to touch the disk
'Prefs.Value("IgnoreUser") = pIgnoreUser
'Prefs.Value ("IgnoreGroup") = pIgnoreGroup
'Prefs.Value("ComputerIdleAfterNumSeconds") = pComputerIdleAfterNumSeconds
'Prefs.Value("IdleLoopDelaySeconds") = pIdleLoopDelaySeconds
'Prefs.Value("WaitForUserPromptSeconds") = pWaitForUserPromptSeconds
'Prefs.Value("WindowMessage") = pWindowMessage
'Prefs.Value("WindowTitle") = pWindowTitle
'Prefs.Sync
LogToFile(CurrentMethodName + ": Received user exception = " + str(pIgnoreUser) )
LogToFile(CurrentMethodName + ": Received group exception = " + str(pIgnoreGroup) )
LogToFile(CurrentMethodName + ": Received ComputerIdleAfterNumSeconds = " + str(pComputerIdleAfterNumSeconds) )
LogToFile(CurrentMethodName + ": Received IdleLoopDelaySecond, = " + str(pIdleLoopDelaySeconds) )
LogToFile(CurrentMethodName + ": Received WaitForUserPromptSeconds = " + str(pWaitForUserPromptSeconds) )
// Is this user macadmin?
if ( MiscMethods.CurrentUsername(pIgnoreUser) ) then
// It is macadmin, quit the app
LogToFile("Current user is " + pIgnoreUser + ", quiting app")
quit
else
LogToFile("User is not " + pIgnoreUser + ", continuing")
end if
// Is this user an admin?
if ( MiscMethods.CurrentGroup(pIgnoreGroup) ) then
// It is macadmin, quit the app
LogToFile("Current user is an " + pIgnoreGroup + ", quiting app")
quit
else
LogToFile("User is not an " + pIgnoreGroup + ", continuing")
end if
// Hide window from view at start
LogoutWarning.Hide()
// Start IdleThread
LogToFile(CurrentMethodName + ": Running IdleThread")
// start thread to watch for idle
StartIdleWatch()
// exit app now
LogToFile(CurrentMethodName + ": <---")
End Sub
#tag EndEvent
#tag Method, Flags = &h0
Sub forceLogout()
LogToFile(CurrentMethodName + ": --->")
// Testing mode, use say instead of logout
Dim s As Shell
s=New Shell
dim ShellResults as string
s.Mode = 0
// Log
LogToFile(CurrentMethodName + ": START Killing Apps")
// Graceful quit of apps
LogToFile(CurrentMethodName + ": Quiting all launched from /Applications")
s.Execute("ps axxx -o comm | grep ""/Applications"" | grep -v grep | awk -F'.app' '{print $1"".app""}'")
Dim runningapps as string
runningapps = s.Result
// Create New Array for running apps
Dim appArray() as String
// Place each line in new array
appArray=SPLIT(runningapps,EndOfLine)
// For each app in the array try to graceful quit
For Each appPath as string in appArray
if appPath = "" then
Continue
end
LogToFile("Quiting: " + appPath)
s.Execute("osascript -e 'quit app ""appPath""'")
LogToFile(" Exit Code: " + str(s.ErrorCode))
Next
// kill the apps that are open from /Apps
LogToFile(CurrentMethodName + ": Killing all launched from /Applications")
s.Execute("kill -9 `ps axxx | grep ""/Applications"" | awk '{print $1}'`")
LogToFile(CurrentMethodName + ": App Kill Results: " + s.Result)
// Log out our user with force
LogToFile(CurrentMethodName + ": Tell AppleScript to log it out")
// New method to logout with osascript.
s.Execute("osascript -e 'tell application ""System Events"" to keystroke ""q"" using {command down, shift down, option down}'")
LogToFile(CurrentMethodName + ": LogOut AS Results: " + s.Result)
// Log and quit
LogToFile(CurrentMethodName + ": <---")
End Sub
#tag EndMethod
#tag Method, Flags = &h0
Function IdleSeconds() As Integer
// Set up variables for idle time
// Shell result
Dim mIdleSecs As String
// Shell exit code
Dim merrCode As Integer
// Set up shell
Dim s As Shell
s=New Shell
s.Mode = 0
// Check idle time
//s.Execute code to check idle time from USB input devices
s.Execute "/bin/echo $((`/usr/sbin/ioreg -c IOHIDSystem | /usr/bin/sed -e '/HIDIdleTime/ !{ d' -e 't' -e '}' -e 's/.* = //g' -e 'q'` / 1000000000))"
// Set results to mIdleResult
mIdleSecs = s.Result
// Set error code to mIdleError
merrCode = s.ErrorCode
// Log mIdleResult for debugging
// System.Log(System.LogLevelError, "Method: " + midleSecs)
// LogToFile("mIdleSeconds: " + str(mIdleSecs))
Return val(mIdleSecs)
End Function
#tag EndMethod
#tag Method, Flags = &h0
Function makeFolder(mkdirPath As string) As Boolean
// Set up variables for idle time
// Shell result = mkdirPath
// Shell exit code
Dim merrCode As Integer
// Set up shell
Dim s As Shell
s=New Shell
s.Mode = 0
// Check idle time
//s.Execute code to check idle time from USB input devices
s.Execute "mkdir -p /Users/Shared"
// Set results to mIdleResult
mkdirPath = s.Result
// Set error code to mIdleError
merrCode = s.ErrorCode
// Log mIdleResult for debugging
// System.Log(System.LogLevelError, "Method: " + midleSecs)
// LogToFile("mIdleSeconds: " + str(mIdleSecs))
if mkdirPath = "0" then
return true
else
return false
end
End Function
#tag EndMethod
#tag Method, Flags = &h0
Function RemoteControlCheck() As Boolean
// Set up variables for idle time
Dim stablished as String = "ESTABLISHED"
// Shell result
Dim rccheck As String
// Shell exit code
Dim merrCode As Integer
// Set up shell
Dim s As Shell
s=New Shell
s.Mode = 0
// Check idle time
//s.Execute code to check for connection
s.Execute "/usr/sbin/netstat -n | /usr/bin/grep '.5900'| /usr/bin/awk '{print $6}'"
// Set results to rccheck
// Make the entire returned text uppercase in case Apple ever changes the case to CaMeL CaSe, which would break our code:
rccheck = Uppercase(s.Result)
//LogToFile("rccheck: " + rccheck)
// Set error code to merrCode
merrCode = s.ErrorCode
// LogToFile("rccheck: "+ rccheck)
// LogToFile("stablished: "+ stablished)
If ( InStr( rccheck, stablished ) > 0 ) then
return true
else
//LogToFile("rccheck: false")
return false
End if
// System.Log(System.LogLevelError, "Method: " + midleSecs)
// LogToFile("mIdleSeconds: " + str(mIdleSecs))
End Function
#tag EndMethod
#tag Method, Flags = &h0
Sub StartIdleWatch()
// if the new WatchForIdleThread is not created, do it now
if ( pWatchForIdleThread = nil ) then
// instatiate new thread with enumerated type
pWatchForIdleThread = _
new WatchForIdleThread(Int32(eTaskType.StartIdleWatch ))
// add custom methods for run and finished handlers
AddHandler pWatchForIdleThread.Run, WeakAddressOf Thread_WaitForIdleTime
AddHandler pWatchForIdleThread.Finished, WeakAddressOf Thread_Finished
end if
// Run the thread if it's not already running:
if ( pWatchForIdleThread.State <> Thread.Running ) then
// Hide window during idle watch
LogoutWarning.Hide()
// Set label to default countdown time
LogoutWarning.TimeLabel.setString(str(pWaitForUserPromptSeconds))
// run the new thread
pWatchForIdleThread.Run
end if
End Sub
#tag EndMethod
#tag Method, Flags = &h0
Sub StartUserCountDown()
// if the new WatchForIdleThread is not created, do it now
if ( pIdleCountDownThread = nil ) then
// instatiate new thread with enumerated type
pIdleCountDownThread = _
new WatchForIdleThread(Int32(eTaskType.StartUserCountDown ))
// add custom methods for run and finished handlers
AddHandler pIdleCountDownThread.Run, WeakAddressOf Thread_WaitForUserInput
AddHandler pIdleCountDownThread.Finished, WeakAddressOf Thread_Finished
end if
// Run the thread if it's not already running
if ( pIdleCountDownThread.State <> Thread.Running ) then
// run the new thread
pIdleCountDownThread.Run
end if
End Sub
#tag EndMethod
#tag Method, Flags = &h21
Private Sub Thread_Finished(paramThread as WatchForIdleThread)
LogToFile(CurrentMethodName + ": --->")
// Kill the thread that was used to get here
paramThread.Kill
// Found out which thread just finished
select case Int32 ( paramThread.pTaskType )
// If the StartIdleWatch thread just finished
case int32( eTaskType.StartIdleWatch )
// LogToFile(CurrentMethodName + ": Idle time has expired.")
// Show Login Window
LogoutWarning.Show()
// start logout countdown window
StartUserCountDown()
case int32 ( eTaskType.StartUserCountDown )
// LogToFile(CurrentMethodName + ": No user response from countdown.")
// LogToFile(CurrentMethodName + ": LogoutWarning.pMoreTimeAskedFor = " +str(pMoreTimeAskedFor))
// If the user (or anyone) asked for more time
if (pMoreTimeAskedFor) then
// if the user asks for more time, start the idle watch thread again
// Restart Idle Watch
StartIdleWatch()
else
// if the user ran out of time, start the logout
// kill user logins
forceLogout()
end if
else
end select
End Sub
#tag EndMethod
#tag Method, Flags = &h21
Private Sub Thread_WaitForIdleTime(paramThread as WatchForIdleThread)
// Set up new integer to store idle seconds
Dim mIdleResult As Integer
// get current idle seconds
mIdleResult = IdleSeconds()
// LogToFile(CurrentMethodName + " Idle Seconds: " + str(mIdleResult))
// LogToFile(CurrentMethodName + " waiting for " + str(LogoutWarning.pComputerIdleAfterNumSeconds))
// While our idle result is less than max time
while ( mIdleResult < pComputerIdleAfterNumSeconds )
// Wait pIdleLoopDelaySeconds each loop
App.SleepCurrentThread( pIdleLoopDelaySeconds * 1000 )
// Check idle time:
mIdleResult = IdleSeconds()
// Log our time idle
LogToFile(CurrentMethodName + ": Idle Seconds: " + str(mIdleResult))
wend
// while there is a ARD/VNC session, don't idle out (netstat -n | grep '.5900')
while (RemoteControlCheck() )
// Wait pIdleLoopDelaySeconds each loop
App.SleepCurrentThread( pIdleLoopDelaySeconds * 1000 )
// Log
LogToFile(CurrentMethodName + ": Someone is controlling via ARD/VNC, waiting...")
wend
// When there is not remote control
LogToFile(CurrentMethodName + ": No one is controlling via ARD/VNC, continuing...")
End Sub
#tag EndMethod
#tag Method, Flags = &h21
Private Sub Thread_WaitForUserInput(paramThread as WatchForIdleThread)
LogToFile(CurrentMethodName + ": --->")
// Set how long to wait before logging out user, set from global variable for LogOutDelay
Dim pLogoutDelay as Integer = pWaitForUserPromptSeconds
// While we're waiting for the countdown to finish...
While pLogoutDelay >= 0
// LogToFile(CurrentMethodName + "Time Left: " + str(pLogoutDelay))
// Set global variable to the time left
pCountDownTime = pLogoutDelay
// call updateUI to set countdown label
pIdleCountDownThread.UpdateUI()
// take a second away from the time left
pLogoutDelay = pLogoutDelay - 1
// do nothing for 1 second
App.SleepCurrentThread( 1000 ) // sleep 1 second
Wend
// If we're here, the user didn't cancel or log out manaully
// user did not ask for more time
pMoreTimeAskedFor = false
// Log
LogToFile(CurrentMethodName + ": Time Out for Response. Log User Out...")
// Done here
LogToFile(CurrentMethodName + ": <---")
// Return to Thread_Finished
End Sub
#tag EndMethod
#tag Note, Name = Icon
Application Icon use with CC license:
From http://www.flickr.com/photos/23453447@N02/5107438855/sizes/o/in/photostream/
By zyrquel
http://www.flickr.com/photos/23453447@N02/
#tag EndNote
#tag Note, Name = Tests
New builds should be tested for:
Launching
Hiding Dock Icon
Logging to File
Reading Preferences
Reading Idle Time
Countdown Timer starts when idle time reached
Countdown Window Shows
More Time button resets the clock
Log Out Button quits open apps and logs out
Timer Runs out and Auto-Logs Out
Remove Control Blocks logout
Custom Name
Custom Text
defaults write /Library/Preferences/edu.psu.idlelogout.plist IgnoreUser -string clcclmadmin
defaults write /Library/Preferences/edu.psu.idlelogout.plist IgnoreGroup -string user
defaults write /Library/Preferences/edu.psu.idlelogout.plist ComputerIdleAfterNumSeconds -string 10
defaults write /Library/Preferences/edu.psu.idlelogout.plist IdleLoopDelaySeconds -string 5
defaults write /Library/Preferences/edu.psu.idlelogout.plist WaitForUserPromptSeconds -string 120
defaults write /Library/Preferences/edu.psu.idlelogout.plist WindowTitle -string "Our Idle Logout"
defaults write /Library/Preferences/edu.psu.idlelogout.plist WindowMessage "You're going to be logged out\n\n\nDude\!"
#tag EndNote
#tag Property, Flags = &h0
pAppVersion As String = "2.1"
#tag EndProperty
#tag Property, Flags = &h0
pComputerIdleAfterNumSeconds As Integer = 900
#tag EndProperty
#tag Property, Flags = &h0
pCountDownTime As Integer
#tag EndProperty
#tag Property, Flags = &h0
pDefaultPrefsFileName As String = "edu.psu.its.clc.IdleLogoutSettings.plist"
#tag EndProperty
#tag Property, Flags = &h0
pDefaultPrefsFSPath As String = "/Library/CLMadmin/Config/"
#tag EndProperty
#tag Property, Flags = &h0
pIdleCountDownThread As WatchForIdleThread
#tag EndProperty
#tag Property, Flags = &h0
pIdleLoopDelaySeconds As Integer = 60
#tag EndProperty
#tag Property, Flags = &h0
pIgnoreGroup As String = "admin"
#tag EndProperty
#tag Property, Flags = &h0
pIgnoreUser As String = "clmadmin"
#tag EndProperty
#tag Property, Flags = &h0
pMoreTimeAskedFor As Boolean = true
#tag EndProperty
#tag Property, Flags = &h0
Prefs As TTsSmartPreferences
#tag EndProperty
#tag Property, Flags = &h0
pWaitForUserPromptSeconds As Integer = 90
#tag EndProperty
#tag Property, Flags = &h0
pWatchForIdleThread As WatchForIdleThread
#tag EndProperty
#tag Property, Flags = &h0
pWindowMessage As String = "This Mac is now Idle.\n\nClick the ""More Time"" button to continue using the Mac.\n\nOtherwise, an automatic logout will occur and all unsaved documents will be LOST!"
#tag EndProperty
#tag Property, Flags = &h0
pWindowTitle As String
#tag EndProperty
#tag Constant, Name = kEditClear, Type = String, Dynamic = False, Default = \"&Delete", Scope = Public
#Tag Instance, Platform = Windows, Language = Default, Definition = \"&Delete"
#Tag Instance, Platform = Linux, Language = Default, Definition = \"&Delete"
#tag EndConstant
#tag Constant, Name = kFileQuit, Type = String, Dynamic = False, Default = \"&Quit", Scope = Public
#Tag Instance, Platform = Windows, Language = Default, Definition = \"E&xit"
#tag EndConstant
#tag Constant, Name = kFileQuitShortcut, Type = String, Dynamic = False, Default = \"", Scope = Public
#Tag Instance, Platform = Mac OS, Language = Default, Definition = \"Cmd+Q"
#Tag Instance, Platform = Linux, Language = Default, Definition = \"Ctrl+Q"
#tag EndConstant
#tag Enum, Name = eTaskType, Type = Int32, Flags = &h0
StartIdleWatch
StartUserCountDown
#tag EndEnum
#tag ViewBehavior
#tag ViewProperty
Name="pAppVersion"
Group="Behavior"
InitialValue="1.1"
Type="String"
EditorType="MultiLineEditor"
#tag EndViewProperty
#tag ViewProperty
Name="pComputerIdleAfterNumSeconds"
Group="Behavior"
InitialValue="900"
Type="Integer"
#tag EndViewProperty
#tag ViewProperty
Name="pCountDownTime"
Group="Behavior"
Type="Integer"
#tag EndViewProperty
#tag ViewProperty
Name="pDefaultPrefsFileName"
Group="Behavior"
InitialValue="edu.psu.its.clc.IdleLogoutSettings.plist"
Type="String"
EditorType="MultiLineEditor"
#tag EndViewProperty
#tag ViewProperty
Name="pDefaultPrefsFSPath"
Group="Behavior"
InitialValue="/Library/CLMadmin/Config/"
Type="String"
EditorType="MultiLineEditor"
#tag EndViewProperty
#tag ViewProperty
Name="pIdleLoopDelaySeconds"
Group="Behavior"
InitialValue="60"
Type="Integer"
#tag EndViewProperty
#tag ViewProperty
Name="pIgnoreGroup"
Group="Behavior"
InitialValue="admin"
Type="String"
EditorType="MultiLineEditor"
#tag EndViewProperty
#tag ViewProperty
Name="pIgnoreUser"
Group="Behavior"
InitialValue="macadmin"
Type="String"
EditorType="MultiLineEditor"
#tag EndViewProperty
#tag ViewProperty
Name="pMoreTimeAskedFor"
Group="Behavior"
InitialValue="true"
Type="Boolean"
#tag EndViewProperty
#tag ViewProperty
Name="pWaitForUserPromptSeconds"
Group="Behavior"
InitialValue="90"
Type="Integer"
#tag EndViewProperty
#tag ViewProperty
Name="pWindowMessage"
Group="Behavior"
InitialValue="'This Mac is idle. Click the """"More Time"""" button to continue using the Mac. Otherwise, an automatic logout will occur and all unsaved documents will be LOST!"
Type="String"
#tag EndViewProperty
#tag ViewProperty
Name="pWindowTitle"
Group="Behavior"
Type="String"
#tag EndViewProperty
#tag EndViewBehavior
End Class
#tag EndClass