Here's an example of a class that can be leveraged to interact with modems in an effort to retrieve banners:
class AtHayesScreenDialer
def initialize(screen_session_name, tty_dev_path, at_init_str="AT S7=45 S0=0 L1 V1 X4 &c1 E1 Q0")
@screen_session_name = "#{screen_session_name}_#{rand(36**8).to_s(36)}"
@screen_session_rc_file = "/tmp/screenrc_#{@screen_session_name}"
@screen_session_log_file = "/tmp/screen_#{@screen_session_name}.log"
@press_enter = sprintf("\r")
@screen_cmd = "screen -p 0 -S #{@screen_session_name} -X stuff"
begin
# Setup GNU screen session's flushing of logfile buffer to be real-time
File.open(@screen_session_rc_file, 'w') do |f|
f.puts "logfile '#{@screen_session_log_file}'"
f.puts "logfile flush 0"
end
# Custom rc file, log, and start in deteached mode with session name
`screen -c #{@screen_session_rc_file} -L -d -m -S #{@screen_session_name} #{tty_dev_path}`
sleep 3 # Let's wait a bit to ensure our screen session is ready...
puts "\nIntializing Screen Session: #{@screen_session_name}"
print "Sent '#{at_init_str}' Command..."
`#{@screen_cmd} "#{at_init_str}#{@press_enter}"`
sleep 1
puts self.check_response
return 0
rescue => e
puts "ERROR!!! #{e.class} #{e} #{e.backtrace}"
self.close
return 1
end
end
def dump
begin
return File.read(@screen_session_log_file, :encoding=>"BINARY")
rescue => e
puts "ERROR!!! #{e.class} #{e} #{e.backtrace}"
self.close
return 1
end
end
def close
begin
`screen -S #{@screen_session_name} -X quit`
File.unlink(@screen_session_rc_file)
File.unlink(@screen_session_log_file)
return 0
rescue => e
puts "ERROR!!! #{e.class} #{e} #{e.backtrace}"
return 1
end
end
# Pass in 0 as param for key_delay_seconds if no key delay is desired...
def press_key(key,times=1,key_delay_seconds=1)
(1..times).each do
printf("%s", key)
sleep key_delay_seconds
end
return
end
def check_response
serial_output = File.read(@screen_session_log_file, :encoding=>"BINARY")
if serial_output.nil?
response = nil
else
response = serial_output.split(/\r\n/)[-1]
unless response.nil?
response = response.strip.chomp
end
end
case response
when "OK"
return :OK
when /CONNECT (9600|38400|115200)/
return response
when "ERROR"
return :ERROR
when /ATDT[0-9],[0-9]/
return 0
when "NO CARRIER"
return :NO_CARRIER
when "BUSY"
return :BUSY
when "VOICE"
return :VOICE
end
end
def command_mode
begin
`#{@screen_cmd} "+++"`
sleep 1
return 0
rescue => e
puts "ERROR!!! #{e.class} #{e} #{e.backtrace}"
self.close
return 1
end
end
def data_mode
begin
`#{@screen_cmd} "ATO#{@press_enter}"`
sleep 1
return 0
rescue => e
puts "ERROR!!! #{e.class} #{e} #{e.backtrace}"
self.close
return 1
end
end
def hangup
begin
print "\nHanging Up. Sending 'ATH' Command..."
`#{@screen_cmd} "ATH#{@press_enter}"`
sleep 1
puts self.check_response
return 0
rescue => e
puts "ERROR!!! #{e.class} #{e} #{e.backtrace}"
self.close
return 1
end
end
def reset
begin
print "\nHanging Up. Sending 'ATH' Command..."
`#{@screen_cmd} "ATZ#{@press_enter}"`
sleep 1
puts self.check_response
return 0
rescue => e
puts "ERROR!!! #{e.class} #{e} #{e.backtrace}"
self.close
return 1
end
end
def dial(phone_num, call_length_seconds, dial_prefix=nil, banner_grap=true)
begin
call_started = Time.now
call_length_status = Time.now - call_started
unless dial_prefix.nil?
print "Dialing #{dial_prefix},#{phone_num} for a duration of #{call_length_seconds} seconds..."
`#{@screen_cmd} "ATDT#{dial_prefix},#{phone_num}#{@press_enter}"`
else
print "Dialing #{phone_num} for a duration of #{call_length_seconds} seconds"
`#{@screen_cmd} "ATDT#{phone_num}#{@press_enter}"`
end
until call_length_status > call_length_seconds
current_response = self.check_response
# If we get a CONNECT response, pass a few carriage returns to get a banner response...
if current_response =~ /CONNECT (9600|38400|115200)/
puts current_response
`#{@screen_cmd} #{@press_enter}`
sleep 1
`#{@screen_cmd} #{@press_enter}`
sleep 1
`#{@screen_cmd} #{@press_enter}`
`#{@screen_cmd} #{@press_enter}`
`#{@screen_cmd} #{@press_enter}`
sleep 3
if banner_grap == true
self.command_mode
self.hangup
self.reset
return 0
#else
#jack with the remote session
end
end
print "."
call_length_status = Time.now - call_started
sleep 1
end
puts "CALL LENGTH MET (#{call_length_seconds} seconds)."
self.command_mode
self.hangup
puts self.check_response
return 0
rescue => e
puts "ERROR!!! #{e.class} #{e} #{e.backtrace}"
self.close
return 1
end
end
end