Created
January 24, 2010 09:03
-
-
Save digitalknk/285112 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#Ruby | |
Area = '555' # My area code | |
Tz = -8 # Time zone (GMT-8) | |
# Speed dial entries. Format: "key" => "number" | |
Speeddial = { | |
'0' => '555-5555', # Home | |
'1' => '1 555 555-5555', # Another Number | |
'411' => '1 800 466 4411', # Google 411 | |
'911' => '911@F9', # Emergency - Not really using this so it's not setup | |
'303' => '[email protected]', # Blueface speaking clock | |
'612' => '[email protected]', # FWD speaking clock | |
} | |
# Serviced domains, must be in lowercase! | |
Domains = ['sipsorcery.com','174.129.236.7'] | |
# Excluded Prefixes. Provides a safeguard against accidentally calling premium | |
# numbers. Accepts both strings and patterns, spaces ignored | |
ExcludedPrefixes = [ | |
' 1 (900 | 976 | 809)', # USA Premium | |
'44 (9 | 55 | 87 (0|1))', # UK Premium | |
'44 84 (4|5)', # UK Local Premium | |
'44 70', # UK Personal Premium | |
'43 (8|9)', # Austria Premium | |
'32 (7|90)', # Belgium Premium | |
'45 (1 | 50 (1|2|3) | 70 (1|2))', # Denmark Premium | |
'45 (8|9) 0', # Denmark Premium (...) | |
'33 (7|9)', # France Premium | |
'49 (1 | 900)', # Germany Premium | |
'39 [^3]', # Italy Premium (...) | |
'31 (14 | 6 (3|8|9) | 8 | 9)', # Netherlands Premium (...) | |
'48 (39 | (2|7|8) 0)', # Poland Premium | |
'46 9 (00 | 39 | 44)', # Sweden Premium | |
'41 90 (0|1|6)', # Switzerland Premium | |
] | |
# Providers: "key" => "template". Template format: prefix@Provider | |
VSPtab = { | |
'0' => '00 @ Freecall', # Future-nine default route | |
'2' => '02 @ F9', # Future-nine grey route | |
'3' => '03 @ Freecall', # Future-nine white route | |
'4' => '04 @ Freecall', # Future-nine premium route | |
'5' => '@ Gizmo5', # Gizmo5 | |
} | |
# ******************** G o o g l e V o i c e ***************************** | |
# !!!!!!!!!!!! Make sure to enter your credentials below !!!!!!!!!!!!! | |
def googleVoice | |
sys.GoogleVoiceCall('[email protected]','myPassword:','myCallBackNumber',@num,'.*',7) # Typically would use a Free DID pointing to a sip account or your Gizmo5 747 account number as a callback number. | |
end | |
# ******************** s e l e c t V S P ******************************* | |
def selectVSP # VoIP provider selection | |
# Reject calls to premium numbers unless VSP was forced | |
ExcludedPrefixes.each { |p| p.gsub!(/\s*/,''); sys.Respond(503,"Calls to #{$1}* not allowed") if @num =~ /^(#{p})/ } | |
case @num | |
when /^1([2-9]\d\d)/ # North America | |
case $1 # check area code | |
when "808", "907", "867" # AK, HI, Canada Yukon | |
route(4,"Destination - Alaska, Hawaii, Yukon") | |
when /(800|866|877|888|747)/ # Toll-free and 1-747 calling | |
route(5,"Destination - US toll-free or G5") | |
else | |
googleVoice | |
sys.Log("GoogleVoiceCall failed, routing thru Freecall") | |
route(4,"Destination - North America") | |
end | |
# when /^972(5|6)/ # Israel mobile | |
# route(3,"Destination - Israel mobile") | |
# else | |
# route(0,"Default route applied") | |
end | |
end | |
# ************************** C A L L S W I T C H ********************** | |
def callswitch(num,*args) | |
route # Initialize vars | |
@num = num unless @num = Speeddial[num] # If there is speed dial entry for it... | |
@l = "URI dialing: #{@num}" # Assume URI dialing | |
unless @num =~ /@/ # If we already have URI, skip all number processing | |
@num.gsub!(/%(..)/) {$1.to_i(16).chr} # Convert %hh into ASCII | |
if @num =~ /^#(.)(.*)/ # If number starts with '#' | |
@p = $1; @num = $2 # next char is VSP code | |
end | |
@num.gsub!(/[^0-9*+]/,'') # Delete all fancy chars (only digits, '+' and '*' allowed) | |
# sub! below removes prefixes: | |
# '+' - international format | |
# 00 - European style international prefix (00) | |
# 011 - US style international prefix (011) | |
unless @num.sub!(/^(\+|00|011)/,'') # If no international prefix, process special cases below | |
case @num | |
when /^[2-9]\d{6}$/ # Local call, 7-digit number | |
@num = "1#{Area}#{@num}" # prefix it with country and area code | |
when /^[01]?([2-9]\d{9})/ # US number with or without "1" country code | |
@num = '1' + $1 # add country code and truncate number to 10-digit | |
when /^\*/ # Voxalot voicemail, echotest & other special numbers | |
else | |
sys.Respond(603,'Wrong number, check & dial again') | |
end | |
end | |
sys.Log("Number in ENUM format: #{@num}") | |
@l = "Forced routing to provider #{@p}, template '#{VSPtab[@p]}'" # Assume user explicitly selected VSP | |
if @p.empty? # Automatic VSP selection? | |
# Invoke selectVSP prior to ENUM lookup just in case we need to modify @num | |
route # re-initialize variables | |
selectVSP # Pick appropriate provider for the call | |
if enumuri = sys.ENUMLookup("+#{@num}.e164.org") # Check if NAPTR exists for the number | |
sys.Log("ENUM entry found: '#{enumuri}'") # If yes, call that URI | |
sys.Dial(enumuri) # if call failed, call via regular VSP. | |
status() # If this is not what you want, add "return" | |
sys.Log("Call to #{enumuri} failed (#{@reason}), will call again via regular VoIP provider") | |
end | |
end # @p.empty | |
end # URI | |
dial(*args) # dial selected number or URI | |
end | |
# ******************************* D I A L ******************************** | |
def dial(*args) | |
sys.Log(@l) unless @l.empty? # for the record :) | |
if tpl=VSPtab[@p.to_s] # if provider is in our table | |
tpl.gsub!(/\s*/,'') # Remove spaces | |
@num = tpl.gsub(/@/,@num+'@') # Insert number before '@' | |
end | |
sys.Dial(@num,*args) # Dial | |
status() # We shouldn't be here! Get error code... | |
sys.Log("Call failed: code #{@code}, #{@reason}") | |
end | |
# ****************************** R O U T E ******************************* | |
def route(p='', l='') | |
@p = p; @l = l | |
end | |
# ***************************** S T A T U S ****************************** | |
def status | |
if (ptr = sys.LastDialled[0]).nil? | |
@code = 487; @reason = 'Cancelled by Sipsorcery' | |
else | |
ptr = ptr.TransactionFinalResponse | |
@code = ptr.StatusCode; @reason = ptr.ReasonPhrase | |
# sys.Log("#{ptr.ToString()}") | |
end | |
end | |
# ******************************* M A I N ******************************** | |
begin | |
sys.Log("** Call from #{req.Header.From.ToString()} to #{req.URI.User} **") | |
t = Time.now + ((Tz+8)*60*60) # Get current time and adjust to local. SS Server is in GMT-8 | |
sys.Log(t.strftime('Local time: %c')) | |
if sys.In # If incoming call... | |
name = req.Header.from.FromURI.User.to_s # Get caller ID | |
# Prepend 10-digit numbers with "1" (US country code) and remove 011 prefix (if present) | |
name = ('1' + name) if name =~ /^[2-9]\d\d[2-9]\d{6}$/ | |
name.sub!(/^011/,'') | |
sys.Log("FromName: '#{name}'") | |
# Set FromName for sys.Dial. Change FromURI when forwarding to @local, or | |
# else Bria won't find contact in its phonebook! | |
sys.SetFromHeader(name, nil, nil) | |
if sys.IsAvailable() # If my ATA is registered | |
callswitch("#{sys.Username}@local[fu=#{name}]") # forward all incoming calls to it | |
elsif (8..23) === t.hour # else forward calls to my home | |
sys.Log("#{sys.Username} is not online, forwarding call to home number...") | |
callswitch("0",35) # Note that '0' is in my speed dial list | |
end | |
sys.Respond(480, "#{sys.Username} Not online") # switch to voice mail | |
else # Outbound call ... | |
# check if it's URI or phone number. | |
# If destination's host is in our domain, it's a phone call | |
num = req.URI.User.to_s; reqHost = req.URI.Host.to_s # Get User and Host | |
host = reqHost.downcase.slice(/[^:]+/) # Convert to lowercase and delete optional ":port" | |
num << '@' << reqHost unless Domains.find {|x| x == host} # URI dialing unless host is in our domain list | |
callswitch(num) | |
end | |
sys.Respond(@code,@reason) # Forward error code to ATA | |
rescue | |
# Gives a lot more details at what went wrong (borrowed from Myatus' dialplan) | |
sys.Log("** Error: " + $!) unless $!.to_s =~ /Thread was being aborted./ | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment