Retrospect Insert Tape Issue
					By: James Reynolds - Revised: 2014-01-23 richard
Introduction
To be notified by email that Retrospect 5.x or 6.x needs a tape change, you have to enable media request timeout. Media request timeout will cancel a backup.
  
  James will cover how we used Scripting UI with AppleScript to give use the functionality we wanted from Retrospect when it requests a tape. Like repeat the email to remind us periodiaclly (about one hour), not send emails at certain times (like late nights & weekends), and email us when the tape request dialog is taken care of.
What is the issue?
To be notified by email that Retrospect 5.x or 6.x needs a tape change, you have to enable media request timeout. Media request timeout will cancel a backup. So if you are running a backup, and it asks for a new tape, it will email you about it *after* it cancels the backup. So verification does not occur (if you are doing verification), and you have to start the backup over once you put the new tape in.  
  This might not be such a bad idea in some cases, but not the majority of the time, especially when starting a new backup. For starters, who has the ability to sit in front of the backup server so that they know when a new tape is needed.  
  What we wanted was Retrospect to email us when it requests a tape, repeat the email to remind us periodically (about one hour), not send emails at certain times (like late nights & weekends), and email us when the tape request dialog is taken care of. Anyone familiar with the network monitoring software 
Intermapper knows where we are coming from. Intermapper does all of this.
Workaround
Our solution is to enable UI Scripting on the Macs we run the Retrospect server and use a AppleScript to detect the UI components in the tape request window. If the components are present, then it knows the tape request window is active. If the components are not present, it knows that there is no tape request window active.  
  So using UI Scripting, we can tell when the tape request window is up, and then the rest of the logic, when to email and such, is handled by the AppleScript.  
What is UI Scripting?  UI Scripting is a feature new in Mac OS X 10.3 that allows you to control applications through the graphical user interface, whether or not the applications are "AppleScriptable" or not. Any application that uses Apple's API for windows and widgets are scriptable through UI Scripting.  
  If you want to customize the way our script checks for the UI elements, you will need a tool to inspect the Retrospect UI. Apple provides a tool named 
UI Element Inspector. Another tool is 
PreFab UI Browser (which is what we use).  
  Read more about 
UI Scripting.  
  Read how to enable 
UI Scripting.
Script
To use the script, you first have to enable UI Scripting (see above link). Then you need to have your Retrospect server autologin (best to put it in a secure room). Add the script to Login's StartupItems (found in System Preferences, Accounts, StartupItems). The script needs to always be running.  
  Here is the script. Please be aware, we are still testing it to make sure everything works as expected. Consider it Beta software.
Or view it here:
global email_address
  global messageSent
  global idle_timer
  global messageSentResetTime
  global messageSentResetCountdown
  global email_start_time
  global email_end_time
  global email_days
  
  on run
       -- This is the email address that will get emails (Mail.app must be configured)
       set email_address to {"youremailhere@yourschoolhere.edu"}
       -- This is how many seconds pass between each check.
       set idle_timer to 120 -- seconds
       -- This next number is multiped by idle_timer to get the number of seconds that must pass before a second reminder message is sent
       set messageSentResetTime to 30 -- multiple this by idle_timer, result is seconds
       -- This is the time that emails will start sending
       set email_start_time to 9
       -- This is the time that emails will stop sending
       set email_end_time to 20
       -- These are the days that emails send
       set email_days to {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday"}
       ----------------------------------------
       -- Don't change the following
       set messageSent to false
       set messageSentResetCountdown to messageSentResetTime
  end run
  
  on idle
       -- Make sure Retrospect is running before doing anything
       try
            tell application "Finder"
                 set process_list to name of every process
                 if process_list does not contain "Retrospect" then
                      return idle_timer
                 end if
            end tell
       on error
            return idle_timer
       end try
       -- Let user know why Retrospect is going to pop in front
       try
            activate
            display dialog "Checking for new tape" giving up after 3
       end try
       -- Check to see if Tape request window is open
       set tapeRequestWindowActive to false
       try
            with timeout of 8 seconds
                 activate application "Retrospect"
                 tell application "System Events"
                      tell process "Retrospect"
                           -- search every window for the Tape request buttons
                           repeat with i from 1 to count of every window
                                try
                                     get value of button "Stop" of window i -- This will produce an error if the tape request window isn't open
                                     get value of button "Eject" of window i -- This will produce an error if the tape request window isn't open
                                     -- if execution reaches this point, then Retrospect needs attention
                                     set tapeRequestWindowActive to true
                                end try
                           end repeat
                      end tell
                 end tell
            end timeout
       on error mes number num
            if num is not equal to -1712 then -- -1712 is the Timeout error (I am not 100% sure about that)
                 try
                      activate
                      display dialog "Error: " & mes & " Number: " & num giving up after 30
                 end try
            end if
       end try
       if tapeRequestWindowActive then
            try
                 say "Backup server needs new tape"
            end try
            if messageSent is false then
                 -- Send message
                 set theSubject to "Retrospect script: attention needed"
                 set theBody to "Please swap tapes."
                 try
                      activate
                      display dialog "Sending mail: " & theBody giving up after 5
                 end try
                 sendMail(theSubject, theBody, email_address)
                 set messageSent to true
                 set messageSentResetCountdown to messageSentResetTime
            else
                 -- Count down to send reminder notification
                 if timeWindow() then
                      set messageSentResetCountdown to messageSentResetCountdown - 1
                      if messageSentResetCountdown is less than 0 then
                           -- Timer has expired, send a reminder message
                           set messageSent to false
                      end if
                 end if
            end if
       else
            if messageSent then
                 -- Send a message saying everything is now ok
                 set theSubject to "Retrospect script: I'm happy"
                 set theBody to "Tapes have been swapped."
                 try
                      activate
                      display dialog "Sending mail: " & theBody giving up after 5
                 end try
                 sendMail(theSubject, theBody, email_address)
                 set messageSent to false
            end if
       end if
       return idle_timer
  end idle
  
  on timeWindow()
       --check to see if the day and time are ok to send messages
       set theDate to current date
       set timestr to time string of theDate
       set oldTIDs to AppleScript's text item delimiters
       set AppleScript's text item delimiters to {":"}
       set theHour to text item 1 of timestr
       set AMPM to word 4 of timestr
       if theHour is equal to "12" then
            set theHour to theHour - 12
       end if
       if AMPM is equal to "PM" then
            set theHour to theHour + 12
       end if
       set timeCheck to false
       if theHour as number is greater than email_start_time then
            if theHour as number is less than email_end_time then
                 set timeCheck to true
            end if
       end if
       set dayCheck to false
       set todays_day to weekday of theDate as string
       if email_days contains todays_day then
            set dayCheck to true
       end if
       if timeCheck then
            if dayCheck then
                 return true
            end if
       end if
       return false
  end timeWindow
  
  on sendMail(theSubject, theBody, email_address)
       if email_address is {} or email_address is "" or email_address is {""} or theBody is "" then return
       set email_address to email_address as string
       try
            tell application "Mail"
                 set theEmail to make new outgoing message with properties {subject:theSubject, content:theBody & return & return}
                 tell theEmail
                      make new to recipient at end of to recipients with properties {name:"", address:email_address}
                 end tell
                 send theEmail
            end tell
       on error mes number num
            try
                 activate
                 display dialog mes giving up after 10
            end try
       end try
  end sendMail