Incoming Dial Plan
Incoming Dial Plan
Being a new user I am trying to tweak my sipsorcery settings.
In general everything is working just fine but I have one small matter that I'm trying to resolve and think an incoming dial plan may be what is needed.
I have three SIP based lines connecting to me at Sipsorcery. Service 1 provides a incoming PSTN number and I also use it for all outgoing calls. Service 2 and Service 3 provide me with alternative incoming numbers from the PSTN .
Service 1 and Service 2 present to calling line ID in the correct format: 0xxxxxxxxxx
For reasons I can't fathom (but presumably because the service provider configures it in this manner) Service 3 presents the number as 44xxxxxxxxxx
The result of this is that I can simply return calls routed via Service 1 and 2 but I have to manually dial any numbers that I miss which are routed via Service 3.
So I'd like to configure an incoming dial plan that simply passes calls via Services 1 and 2 to the ATA without any additional changes but calls via Service 3 need to have the CLID amended to remove the '44' country code and replace it with a '0'.
Is that possible with a dial plan? If so, is there anywhere I can find the documentation to write that bit of code with Ruby?
Andrew
In general everything is working just fine but I have one small matter that I'm trying to resolve and think an incoming dial plan may be what is needed.
I have three SIP based lines connecting to me at Sipsorcery. Service 1 provides a incoming PSTN number and I also use it for all outgoing calls. Service 2 and Service 3 provide me with alternative incoming numbers from the PSTN .
Service 1 and Service 2 present to calling line ID in the correct format: 0xxxxxxxxxx
For reasons I can't fathom (but presumably because the service provider configures it in this manner) Service 3 presents the number as 44xxxxxxxxxx
The result of this is that I can simply return calls routed via Service 1 and 2 but I have to manually dial any numbers that I miss which are routed via Service 3.
So I'd like to configure an incoming dial plan that simply passes calls via Services 1 and 2 to the ATA without any additional changes but calls via Service 3 need to have the CLID amended to remove the '44' country code and replace it with a '0'.
Is that possible with a dial plan? If so, is there anywhere I can find the documentation to write that bit of code with Ruby?
Andrew
Re: Incoming Dial Plan
While it's logical to implement CID change depending on trunk (Service 1,2,3) it might be easier to do it based on 44 prefix and total length of CID string. Something like this:
Depending on your ATA/IP phone, you may need to play with fd and/or fu modifiers in sys.Dial string.
Code: Select all
if sys.In # If incoming call...
@cid = req.Header.from.FromURI.User.to_s # Get caller ID
@cid = ('0' + $1) if @cid =~ /^44(\d{7,})/ # replace 44 with 0. Note: number must be at least 7 digits
sys.Dial("#{sys.UserName}@local[fd=#{@cid}]")
else
# ... your outbound dial plan
endif
Re: Incoming Dial Plan
I taught this problem might best posted here, since it deals with incoming calls also.
I want to be able to route all incoming Trinidad numbers (1868) that call my main Dial plan to 1 ext ( 1001)
so a call comes in with # 1868xxxxxx i want it to be forwarded to ata 1001 .
I have a feeling it has to be inserted here. thanks
By no way I am stealing this post....thanks
Arampe
I want to be able to route all incoming Trinidad numbers (1868) that call my main Dial plan to 1 ext ( 1001)
so a call comes in with # 1868xxxxxx i want it to be forwarded to ata 1001 .
I have a feeling it has to be inserted here. thanks
Code: Select all
# ******************** i n c o m i n g C a l l *************************
def incomingCall
sys.SetFromHeader(formatNum(@cname || @cid,true), nil, Host) # Set FromName & FromHost for sys.Dial
# Forward call to the bindings (ATA / softphone)
# Change FromURI when forwarding to @local, or else Bria won't find contact in its phonebook!
callswitch("#{@user}@local[fu=#{@cid}]",45) unless (2030..0531) === @t.hour*100 + @t.min # reject incoming calls from 11:30p to 11:31p
@code, @reason = 480, "#{@user} is asleep" unless @code # if nothing else, must be the night hour
@code = 486 if @trunk =~ /IPCOMM/i ## *** temporary fix for IPCOMMS ***
end
# ************************** t o E N U M *******************************
Code: Select all
2.213:5060 to udp:190.83.188.3:5060.
NATKeepAlive 14:42:31:360 sip1(52724): Requesting NAT keep-alive from proxy socket udp:69.59.142.213:5060 to udp:190.83.139.2:1024.
NATKeepAlive 14:42:31:376 sip1(52724): Requesting NAT keep-alive from proxy socket udp:69.59.142.213:5060 to udp:212.150.136.8:57268.
NATKeepAlive 14:42:31:376 sip1(52724): Requesting NAT keep-alive from proxy socket udp:69.59.142.213:5060 to udp:190.83.139.2:5062.
DialPlan 14:42:31:860 sip1(86660): New call from udp:190.83.139.2:1024 successfully authenticated by digest.
DialPlan 14:42:31:876 sip1(86660): Using dialplan 250809 for Out call to sip:250809@sipsorcery.com.
NewCall 14:42:31:876 sip1(86660): Executing script dial plan for call to 250809.
DialPlan 14:42:31:938 sip1(86660): ** Call from "+18687599373" <sip:250809@sipsorcery.com>;tag=5bf539e9 to 250809 **
DialPlan 14:42:31:954 sip1(86660): Local time: 01/26/2012 10:42
DialPlan 14:42:31:970 sip1(86660): UAS call failed with a response status of 603 and Wrong number: '250809', check & dial again.
DialPlan 14:42:31:985 sip1(86660): Dialplan cleanup for 250809.
DialPlan 14:42:32:016 sip1(86660): Dial plan execution completed with normal clearing.
NATKeepAlive 14:42:36:438 sip1(52724): Requesting NAT keep-alive from proxy socket udp:69.59.142.213:5060 to udp:190.213.159.125:1024.
NATKeepAlive 14:42:41:454 sip1(52724): Requesting NAT keep-alive from proxy socket udp:69.59.142.213:5060 to udp:190.83.188.3:5060.
NATKeepAlive 14:42:41:485 sip1(52724): Requesting NAT keep-alive from proxy socket udp:69.59.142.213:5060 to udp:190.83.139.2:1024.
NATKeepAlive 14:42:41:485 sip1(52724): Requesting NAT keep-alive from proxy socket udp:69.59.142.213:5060 to udp:212.150.136.8:57268.
NATKeepAlive 14:42:41:501 sip1(52724): Requesting NAT keep-alive from proxy socket udp:69.59.142.213:5060 to udp:190.83.139.2:5062.
Arampe
Re: Incoming Dial Plan
Yes, incomingCall() is the right place. Caller ID is in the @cid variable, you should check it for 1868 prefix.
You will need to create an individual SIP account for each of your extensions and have your ATA / softphones register to their respective SIP accounts.
Then, if you need to forward incoming call to a particular extension, you need to use callswitch("extensionSIPaccount@local"), additional parameters to your taste If you need to multi-forward to several extensions, use '&' modifier, like this:
callswitch("extension1SIPaccount@local&extension2SIPaccount@local")
You will need to create an individual SIP account for each of your extensions and have your ATA / softphones register to their respective SIP accounts.
Then, if you need to forward incoming call to a particular extension, you need to use callswitch("extensionSIPaccount@local"), additional parameters to your taste If you need to multi-forward to several extensions, use '&' modifier, like this:
callswitch("extension1SIPaccount@local&extension2SIPaccount@local")
Re: Incoming Dial Plan
Thanks mike but I am not sure what to do ...complete noob, I mess around and things work.lol
Need some help to allow all the incoming trinidad calls ( 1868 ) to go to ext 1001...
just 1 ext ( 1001 ) to handle all trindad calls .
the calls hits here : sip:250809@sipsorcery.com
this is my primary account , how do I send it to 1001 ...
thank andy
Need some help to allow all the incoming trinidad calls ( 1868 ) to go to ext 1001...
just 1 ext ( 1001 ) to handle all trindad calls .
the calls hits here : sip:250809@sipsorcery.com
this is my primary account , how do I send it to 1001 ...
thank andy
Re: Incoming Dial Plan
Replace this line:
callswitch("#{@user}@local[fu=#{@cid}]",45) unless (2030..0531) === @t.hour*100 + @t.min
with:
I'm assuming that your ATA is registered to 1001@sipsorcery.com, everything else is registered to your main account.
callswitch("#{@user}@local[fu=#{@cid}]",45) unless (2030..0531) === @t.hour*100 + @t.min
with:
Code: Select all
if @cid =~ /^1868/
callswitch("1001@local[fu=#{@cid}]",45) unless (2030..0531) === @t.hour*100 + @t.min
else
callswitch("#{@user}@local[fu=#{@cid}]",45) unless (2030..0531) === @t.hour*100 + @t.min
end
Re: Incoming Dial Plan
This is what when I adjust my Dial Plan ..
Console shows the following :
{I also changed Dial plan for 1001 which is actually ext (Andy_and_Melly) i said 1001 for simplicity }
Main Dial Plan 250809 :
Console shows the following :
Code: Select all
NATKeepAlive 12:39:01:217 sip1(82552): Requesting NAT keep-alive from proxy socket udp:69.59.142.213:5060 to udp:190.83.188.3:5060.
NATKeepAlive 12:39:01:232 sip1(82552): Requesting NAT keep-alive from proxy socket udp:69.59.142.213:5060 to udp:190.213.159.125:1024.
DialPlan 12:39:01:717 sip1(90720): New call from udp:190.83.139.2:1024 successfully authenticated by digest.
DialPlan 12:39:01:732 sip1(90720): Using dialplan 250809 for Out call to sip:250809@sipsorcery.com.
NewCall 12:39:01:732 sip1(90720): Executing script dial plan for call to 250809.
DialPlan 12:39:01:795 sip1(90720): ** Call from "+18687599373" <sip:250809@sipsorcery.com>;tag=59047cc1 to 250809 **
DialPlan 12:39:01:810 sip1(90720): Local time: 02/03/2012 08:39
DialPlan 12:39:01:810 sip1(90720): UAS call failed with a response status of 603 and Wrong number: '250809', check & dial again.
DialPlan 12:39:01:810 sip1(90720): Dialplan cleanup for 250809.
DialPlan 12:39:02:201 sip1(90720): Dial plan execution completed with normal clearing.
NATKeepAlive 12:39:06:311 sip1(82552): Requesting NAT keep-alive from proxy socket udp:69.59.142.213:5060 to udp:190.83.139.2:1024.
Registrar 12:39:08:764 sip1(82552): Authentication required for 250809@sipsorcery.com from udp:190.83.139.2:1024.
Registrar 12:39:09:186 sip1(82552): Binding update request for 250809@sipsorcery.com from udp:190.83.139.2:1024, expiry requested 300s granted 300s.
{I also changed Dial plan for 1001 which is actually ext (Andy_and_Melly) i said 1001 for simplicity }
Main Dial Plan 250809 :
Code: Select all
# Copyright 2010 Mike Telis
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
require 'mikesgem'
# ************* C O N F I G U R A T I O N S E C T I O N *************** #
Area = '868' # my area code, this will be added to 7-digit dialouts
Tz = -3 # my time zone (GMT format, e.g. Eastern = -5, Central = -6)
# Speed dial entries. Format: "key" => "number" 502-5661-8438
Speeddial = {
'1' => '(347) 561-4880', # Michelle home
'2' => '(646) 573-2819', # Michelle Cell
'3' => '(347) 210-6631', # Vijay Cell
'4' => '(443) 636-7891', # Paro Cell
'5' => '(360) 812-2613', # Dad ipkall usa #
'6' => '008613375798811@powervoip',# Lu Peck Cell
'7' => '203@Nygames[ma=false]', # Vijay home ext
'7599373' => '2508091@local', # Test
'203' => '203@nygames[ma=false]', # Vijay home ext
'204' => '204@server1', # Ecuador ext
'444' => '50256618438@server1', # Ecuador ext
'445' => '50244265673@server1', # Ecuador ext
'266' => 'Bharrath@local[ma=false]', # Dad home
'269' => 'Ashtoniphone@local[ma=false]', # Dad home
'268' => 'Mellyphone@local', # Dad home
'253' => 'amyboodhram@local', # Amy
'264' => 'mmplas@local', # office
'263' => 'Andy_and_Melly@local[ma=false]', # Home
'265' => 'AdeshOffice@local[ma=false]', # adesh
'270' => '00115922271360@voipbusterpro',
'273' => 'donna123@local[ma=false]', # Donna Dos Santos
'275' => '5926243120@Voxalot', # Donna Cell
'274' => '00115926835784@powervoip', # Ignatius cell
'277' => '5922271360@nygames', # Donna Home
'712' => '*#2 454-1234', # San Jose Voice Mail, dial my SJ GV using SFO GV acnt
'713' => '*#1 (415) 335-1234', # San Francisco Voice Mail, dial my SFO GV using SJ GV acnt
'714' => '*#1 (773) 778-1234', # San Francisco Voice Mail, dial my Chicago GV using SJ GV acnt
'411' => '(800) 466-4411', # Google's Directory Assistance, GOOG-411
'200' => '303@sip.blueface.ie&612@fwd.pulver.com',
'300' => '441923287748@Voxalot', # BT speaking clock
'666' => '4153767253@podlinez.net', # CNN Headlines (266 = "CNN")
'677' => '8186882773@podlinez.net', # NPR's most e-mailed stories (677 ="NPR")
'742' => '6506441934@podlinez.net', # Prairie Home Companion's, or PHC's
# News from Lake Wobegon (742 = "PHC")
'932' => '7755333366', # Columbus OH-based national weather (932 = "WEA[ther]")
}
# CNAM table: number in ENUM format => caller's name
CNAM = {
'(212) 555-1212' => 'Dear mom',
'(240) 418-3987' => 'Aunty Tina',
'(718) 908-2828' => 'Ali infinity',
'(718) 656-1001' => 'Michelle Work',
'(443) 850-7625' => 'Aunty Ann Aponte',
'(864) 502-8863' => 'Daddy',
'(347) 857-9902' => 'Aunty Donna Guyana',
'(347) 441-0605' => 'Amy and Richard',
'(347) 561-4880' => 'Michelle Gomez Home',
'(443) 739-9497' => 'Diana Pinky Ramlal cell',
'(315) 895-1479' => 'Rooster Wake Up',
'(646) 573-2819' => 'Michelle Gomez Cell',
'(718) 502-8863' => 'Andy and Melly',
'(718) 879-8933' => 'Vijay Home',
'(347) 210-6631' => 'Vijay Cell',
'(917) 443-2170' => 'Nishal Ramnarine',
'(754) 245-3916' => 'Rachael Diaz',
'(213) 884-6354' => 'Tangir Alam',
'(215) 333-2211' => 'Bratty kid',
}
# Uncomment next line and insert your White Pages API key, if you have it
# WP_key = '702f53d569ee03eerefb1dafa62fe72fc' # White Pages API key
# Uncomment line below to enable misdialing safeguards
# EnableSafeguards = 1
# Excluded Prefixes. Provides a safeguard against accidentally calling premium numbers
ExcludedPrefixes = [
' 1 (900 | 809)', # USA Premium
' 1 \d\d\d 555 1212', # USA Directory assistance
'44 (9 | 55 | 70 | 84 | 87)', # UK Premium
'49 (1 [^567] | 900)', # Germany Premium
'39 (1 | 84 | 89)', # Italy Premium
'420 90', # Czech Premium
'32 (70 | 90\d)', # Belgium Premium
]
# Yet another safeguard, list of blessed country codes
Allowed_Country = %w{
1 33 36 37[0-2] 380 39 41 420 44 49 61 7 86 883 886 90 972 998
}
# My own ENUM database
MyENUM = {
'+1 (408) 334-1234' => 'brother@local', # Brother George
}
# Enum database list
EnumDB = [
MyENUM, # look in MyENUM first
'e164.org',
'e164.info',
'e164.arpa',
'e164.televolution.net',
'enum.org',
]
# Serviced domains, must be in lowercase!
Domains = ['sipsorcery.com','sip.sipsorcery.com','sip1.sipsorcery.com','sip2.sipsorcery.com','69.59.142.213']
Host = 'sipsorcery.com' # Replaces "host" on incoming calls
# Google Voice accounts
GoogleVoice = GV.new '#1', nil, 'Google Voice', :usr => 'fsdsffdff', :pwd => 'brerfdwfw',
:cb => '(305) 760-4525', :match => '7185028863'
PSTN = VSP.new '#2', '${EXTEN:1}@250809', 'SPA3102 at home'
Voipstunt = VSP.new '#3', '00 ${EXTEN}@smartvoip', 'Smartvoip'
Nygames = VSP.new '#4', '${EXTEN:3}@nygames', 'Guyana'
# ******************** s e l e c t V S P *******************************
def selectVSP # VoIP provider selection
case @num
when /(^1([2-9]\d\d)[2-9]\d{6})/ # North America
@num = $1 # Truncate to 11 digits
case $2 # check area code
when "868" # Trinidad
route_to PSTN, "Trinidad & Tobago"
else
route_to GoogleVoice, 'USA/Can' # all other destinations within US & Canada
end
when /^592\d{7}$/ # Guyana
route_to Nygames, "Guyana"
when /^86/ # China
route_to PowerVOIP, 'China'
when /^\*/ # For *500, *600 and other Voxalot services
route_to Voxalot, "Voxalot Services", nil
else
rejectCall(603,"Number's too short, check & dial again") if @num.length < 9
route_to Voipstunt
end
end
# ------------ O P T I O N A L C O N F I G U R A T I O N --------------- #
# ******************** i n c o m i n g C a l l *************************
def incomingCall
sys.SetFromHeader(formatNum(@cname || @cid,true), nil, Host) # Set FromName & FromHost for sys.Dial
# Forward call to the bindings (ATA / softphone)
# Change FromURI when forwarding to @local, or else Bria won't find contact in its phonebook!
if @cid =~ /^1868/
callswitch("Andy_and_Melly@local[fu=#{@cid}]",45) unless (2030..0531) === @t.hour*100 + @t.min
else
callswitch("#{@user}@local[fu=#{@cid}]",45) unless (2030..0531) === @t.hour*100 + @t.min
end
@code, @reason = 480, "#{@user} is asleep" unless @code # if nothing else, must be the night hour
@code = 486 if @trunk =~ /IPCOMM/i ## *** temporary fix for IPCOMMS ***
end
# ************************** t o E N U M *******************************
def to_ENUM num
num.gsub!(/[^0-9*+]/,'') # Delete all fancy chars (only digits, '+' and '*' allowed)
# Check if the number begins with one of international prefixes:
# '+' - international format
# 00 - European style international prefix (00)
# 011 - US style international prefix (011)
num =~ /^(\+|00|011)/ and return $' # if yes, remove prefix and return
case num # Special cases
when /^[2-9]\d{6}$/ # Local call, 7-digit number
'1' + Area + num # prefix it with country and area code
when /^[01]?([2-9]\d{9})/ # US number with or without "1" country code
'1' + $1 # add country code and truncate number to 10-digit
when /^\*/ # Voxalot voicemail, echotest & other special numbers
num # ... as is
else
rejectCall(603,"Wrong number: '#{num}', check & dial again")
end
end
# ****** E N D O F C O N F I G U R A T I O N S E C T I O N ******** #
# ************************** C A L L S W I T C H **********************
def callswitch(num,*args)
@timeout = args[0]
num.gsub!(/%([0-9A-F]{2})/) {$1.to_i(16).chr} # Convert %hh into ASCII
@num = Speeddial[num] || num # If there is speed dial entry for it...
if @num =~ /@/ # If we already have URI, just dial and return
sys.Log("URI dialing: #@num")
dial(@num,*args)
else # Not URI
rexp = VSP.tab.keys.sort {|a,b| b.length <=> a.length}.map {|x| Regexp.escape(x)}.join('|')
if @num =~ /^(#{rexp})/ # If number starts with VSP selection prefix
@num = $'; @forcedRoute = VSP.tab[$1]
@noSafeGuards = (@forcedRoute.fmt =~ /Disable\s*Safe\s*Guards/i)
end
@num = to_ENUM(@num) # Convert to ENUM
rejectCall(503,"Number's empty") if @num.empty?
sys.Log("Number in ENUM format: #{@num}")
if @forcedRoute && !@noSafeGuards
route_to @forcedRoute, "Forced routing!", false # if forced with prefix, skip ENUM, safeguards & VSP selection
else
checkNum if defined?(EnableSafeguards) && !@noSafeGuards
selectVSP # Pick appropriate provider for the call
end
end # URI
end
# *************************** R O U T E _ T O ****************************
def route_to vsp, dest=nil, enum = EnumDB
enum.to_a.each do |db| # if enum enabled, look in all enum databases
if uri = (db.class == Hash)? db[@num] : sys.ENUMLookup("#{@num}.#{db}")
sys.Log("ENUM entry found: '#{uri}' in #{db.class == Hash ? 'local' : db} database")
dial(uri)
end
end # ENUM not found or failed, call via regular VSP
return unless vsp # No VSP - do nothing
uri = vsp.fmt.gsub(/\s+/,'').gsub(/\$\{EXTEN(:([^:}]+)(:([^}]+))?)?\}/) {@num[$2.to_i,$4? $4.to_i : 100]}
dest &&= " (#{dest})"; with = vsp.name; with &&= " with #{with}"
sys.Log("Calling #{formatNum(@num)}#{dest}#{with}")
if vsp.is_gv?
vsp.repeat.times do |i|
@code, @reason = 200, "OK" # assume OK
sys.GoogleVoiceCall *vsp.getparams(uri, i + (vsp.rand ? @t.to_i : 0))
sys.Log("Google Voice Call failed!")
@code, @reason = 603, 'Service Unavailable'
end
else
vsp.repeat.times do
dial(uri, @timeout || vsp.tmo || 300) # Dial, global time-out overrides account
end
end
end
# ******************************* D I A L ********************************
def dial *args
@code, @reason = nil
sys.Dial *args # dial URI
status() # We shouldn't be here! Get error code...
sys.Log("Call failed: code #{@code}, #{@reason}")
end
# ***************************** S T A T U S ******************************
def status
begin
@code, @reason = 487, 'Cancelled by Sipsorcery'
sys.LastDialled.each do |ptr|
if ptr
ptr = ptr.TransactionFinalResponse
@code = ptr.StatusCode; @reason = ptr.ReasonPhrase; break if @code == 200
# sys.Log("#{ptr.ToString()}")
end
end
rescue
end
end
# ************************ r e j e c t C a l l ***************************
def rejectCall code, reason
@code = code; @reason = reason
sys.Respond code, reason
end
# **************************** C H E C K N U M **************************
def checkNum
return if @num.match(/^\D/) # skip if number doesn't begin with a digit
# Reject calls to not blessed countries and premium numbers
# (unless VSP was forced using #n dial prefix)
rejectCall(503,"Calls to code #{formatNum(@num).split(' ')[0]} not allowed") \
unless @num.match "^(#{Allowed_Country.join('|')})"
rejectCall(503,"Calls to '#{formatNum($&)}' not allowed") if @num.match \
'^(' + ExcludedPrefixes.map { |x| "(:?#{x.gsub(/\s*/,'')})" }.join('|') + ')'
end
# ********************** k e y s t o E N U M *************************
def keys_to_ENUM (table)
Hash[*table.keys.map! {|key| to_ENUM(key.dup)}.zip(table.values).flatten]
end
# ************************** g e t T I M E *******************************
def getTime
Time.now + ((Tz+7)*60*60) # Get current time and adjust to local. SS Server is in GMT-8
end
# ******************************* M A I N ********************************
begin
sys.Log("** Call from #{req.Header.From} to #{req.URI.User} **")
sys.ExtendScriptTimeout(15) # preventing long running dialscript time-out
@t = getTime()
sys.Log(@t.strftime('Local time: %c'))
EnumDB.map! {|x| x.class == Hash ? keys_to_ENUM(x) : x } # rebuild local ENUM table
if sys.In # If incoming call...
@cid = req.Header.from.FromURI.User.to_s # Get caller ID
# Prepend 10-digit numbers with "1" (US country code) and remove int'l prefix (if present)
@cid = ('1' + @cid) if @cid =~ /^[2-9]\d\d[2-9]\d{6}$/
@cid.sub!(/^(\+|00|011)/,'') # Remove international prefixes, if any
prs = req.URI.User.split('.') # parse User into chunks
@trunk = prs[-2] # get trunk name
@user = prs[-1] # called user name
# Check CNAM first. If not found and US number, try to lookup caller's name in Whitepages
if !(@cname = keys_to_ENUM(CNAM)[@cid]) && @cid =~ /^1([2-9]\d\d[2-9]\d{6})$/ && defined?(WP_key)
url = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20xml%20where%20url%3D'http%3A%2F%2Fapi.whitepages.com%2Freverse_phone%2F1.0%2F%3Fphone%3D#{$1}%3Bapi_key%3D#{WP_key}'%20and%20itemPath%3D'wp.listings.listing'&format=json"
if js = sys.WebGet(url,4).to_s
@cname, dname, city, state = %w(businessname displayname city state).map {|x| js =~ /"#{x}":"([^"]+)"/; $1}
@cname ||= dname; @cname ||= "#{city}, #{state}" if city && state
end
end
sys.Log("Caller's number: '#{@cid}'"); sys.Log("Caller's name: '#{@cname}'") if @cname
incomingCall() # forward incoming call
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.include?(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
Re: Incoming Dial Plan
It's outbound call, not incoming call:
DialPlan 12:39:01:732 sip1(90720): Using dialplan 250809 for Out call to sip:250809@sipsorcery.com
DialPlan 12:39:01:732 sip1(90720): Using dialplan 250809 for Out call to sip:250809@sipsorcery.com
Re: Incoming Dial Plan
When the exact call goes via my other server this is what happens ...
Now here is what happens when I forward the call to Andy_and_Melly@sipsorcery.com
Weird.....this my Dialplan.
strange why the call does not reach ext Andy_and_Melly@sipsorcery.com
Code: Select all
20): Sending initial register for 250809 and 250809 to udp:174.129.236.7:5060.
ContactRegisterInProgress 13:14:11:848 sip1(2120): Initiating registration for 250809 on sip:174.129.236.7.
NATKeepAlive 13:14:14:504 sip1(1956): Requesting NAT keep-alive from proxy socket udp:69.59.142.213:5060 to udp:190.83.188.3:5060.
NATKeepAlive 13:14:14:504 sip1(1956): Requesting NAT keep-alive from proxy socket udp:69.59.142.213:5060 to udp:190.213.159.125:1024.
DialPlan 13:14:18:770 sip1(4060): Using dialplan Andy_and_Melly for In call to sip:Andy_and_Melly@sipsorcery.com;rinstance=758437.
NewCall 13:14:18:770 sip1(4060): Executing script dial plan for call to Andy_and_Melly.
DialPlan 13:14:18:848 sip1(4060): ** Call from "+18687599373" <sip:250809@74.101.52.90>;tag=as349a4f03 to Andy_and_Melly **
DialPlan 13:14:18:848 sip1(4060): Local time: 02/05/2012 09:14
DialPlan 13:14:18:864 sip1(4060): Caller's number: '250809'
DialPlan 13:14:18:864 sip1(4060): URI dialing: Andy_and_Melly@local[fu=250809]
DialPlan 13:14:18:864 sip1(4060): Commencing Dial with: Andy_and_Melly@local[fu=250809].
DialPlan 13:14:18:895 sip1(4060): Call leg is for local domain looking up bindings for Andy_and_Melly@sipsorcery.com for call leg Andy_and_Melly@local.
DialPlan 13:14:18:895 sip1(4060): 1 found for Andy_and_Melly@sipsorcery.com.
DialPlan 13:14:18:895 sip1(4060): ForkCall commencing call leg to sip:Andy_and_Melly@190.213.159.125:1024.
DialPlan 13:14:18:895 sip1(4060): SIPClientUserAgent Call using alternate outbound proxy of udp:69.59.142.213:5060.
DialPlan 13:14:18:895 sip1(4060): Switching to sip:Andy_and_Melly@190.213.159.125:1024 via udp:69.59.142.213:5060.
DialPlan 13:14:18:895 sip1(4060): SDP on UAC call had public IP not mangled, RTP socket 74.101.52.90:11600.
DialPlan 13:14:19:067 sip1(4060): Information response 100 Trying for sip:Andy_and_Melly@190.213.159.125:1024.
DialPlan 13:14:19:082 sip1(4060): Information response 180 Ringing for sip:Andy_and_Melly@190.213.159.125:1024.
DialPlan 13:14:19:082 sip1(4060): UAS call progressing with Ringing.
NATKeepAlive 13:14:19:536 sip1(1956): Requesting NAT keep-alive from proxy socket udp:69.59.142.213:5060 to udp:190.83.139.2:1024.
NATKeepAlive 13:14:19:551 sip1(1956): Requesting NAT keep-alive from proxy socket udp:69.59.142.213:5060 to udp:190.83.139.2:5062.
NATKeepAlive 13:14:24:629 sip1(1956): Requesting NAT keep-alive from proxy socket udp:69.59.142.213:5060 to udp:190.83.188.3:5060.
NATKeepAlive 13:14:24:629 sip1(1956): Requesting NAT keep-alive from proxy socket udp:69.59.142.213:5060 to udp:190.213.159.125:1024.
DialPlan 13:14:28:708 sip1(4060): Response 200 OK for sip:Andy_and_Melly@190.213.159.125:1024.
DialPlan 13:14:28:708 sip1(4060): SDP on UAC response had public IP not mangled, RTP socket 190.213.159.125:16400.
DialPlan 13:14:28:708 sip1(4060): Cancelling all call legs for ForkCall app.
DialPlan 13:14:28:708 sip1(4060): Answering client call with a response status of 200.
DialPlan 13:14:28:770 sip1(4060): Dial command was successfully answered in 9.88s.
DialPlan 13:14:28:770 sip1(4060): Dialplan cleanup for 250809.
DialPlan 13:14:29:036 sip1(4060): Dial plan execution completed with normal clearing.
NATKeepAlive 13:14:29:661 sip1(1956): Requesting NAT keep-alive from proxy socket udp:69.59.142.213:5060 to udp:190.83.139.2:1024.
NATKeepAlive 13:14:29:676 sip1(1956): Requesting NAT keep-alive from proxy socket udp:69.59.142.213:5060 to udp:190.83.139.2:5062.
ContactRegisterInProgress 13:14:30:051 sip1(2120): Checking SIP Provider registration for sipgatedonna.
ContactRegisterInProgress 13:14:30:051 sip1(2120): Sending initial register for 250809 and sipgatedonna to udp:204.155.28.10:5060.
ContactRegisterInProgress 13:14:30:176 sip1(2120): Initiating registration for 250809 on sip:sipgate.com.
ContactRegistered 13:14:30:239 sip1(2120): Contact successfully registered for 250809 on sip:sipgate.com, expiry 60s.
NATKeepAlive 13:14:34:755 sip1(1956): Requesting NAT keep-alive from proxy socket udp:69.59.142.213:5060 to udp:190.83.188.3:5060.
NATKeepAlive 13:14:34:755 sip1(1956): Requesting NAT keep-alive from proxy socket udp:69.59.142.213:5060 to udp:190.213.159.125:1024.
Now here is what happens when I forward the call to Andy_and_Melly@sipsorcery.com
Code: Select all
NATKeepAlive 13:25:58:049 sip1(1956): Requesting NAT keep-alive from proxy socket udp:69.59.142.213:5060 to udp:190.83.139.2:1024.
DialPlan 13:26:02:658 sip1(4060): New call from udp:190.83.139.2:1024 successfully authenticated by digest.
DialPlan 13:26:02:658 sip1(4060): Using dialplan 250809 for Out call to sip:Andy_and_Melly@sipsorcery.com.
NewCall 13:26:02:674 sip1(4060): Executing script dial plan for call to Andy_and_Melly.
DialPlan 13:26:02:752 sip1(4060): ** Call from "+18687599373" <sip:250809@sipsorcery.com>;tag=54d63557 to Andy_and_Melly **
DialPlan 13:26:02:752 sip1(4060): Local time: 02/05/2012 09:26
DialPlan 13:26:02:768 sip1(4060): UAS call failed with a response status of 603 and Wrong number: '', check & dial again.
DialPlan 13:26:02:768 sip1(4060): Dialplan cleanup for 250809.
NATKeepAlive 13:26:03:096 sip1(1956): Requesting NAT keep-alive from proxy socket udp:69.59.142.213:5060 to udp:190.83.139.2:5062.
Code: Select all
# Copyright 2010 Mike Telis
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
# Donna123 - sipgate - adesh@vijaysconsulting.com - ashton1 - (518) 351-1348
# Amyboodhram - sipgate - adesh@mmplas.com - ashton1 - (650) 284-1494
# Andy and Melly - sipgate - arampe@gmail.com - ashton1 -
require 'mikesgem'
# ************* C O N F I G U R A T I O N S E C T I O N *************** #
Area = '868' # my area code, this will be added to 7-digit dialouts
Tz = -3 # my time zone (GMT format, e.g. Eastern = -5, Central = -6)
# Speed dial entries. Format: "key" => "number"
Speeddial = {
'1' => '(347) 561-4880', # Michelle home
'2' => '(646) 573-2819', # Michelle Cell
'3' => '(347) 210-6631', # Vijay Cell
'4' => '(443) 636-7891', # Paro Cell
'5' => '(360) 812-2613', # Dad ipkall usa #
'6' => '008613375798811@powervoip',# Lu Peck Cell
'7' => '203@Nygames[ma=false]', # Vijay home ext
'7599373' => '2508091@local', # Test
'203' => '203@Nygames', # Vijay home ext
'204' => '(213) 884-6354', # Tangir Alam
'444' => 'ecuador@local', # Ecuador ext
'266' => 'Bharrath@local', # Dad home
'269' => 'Ashtoniphone@local', # Dad home
'268' => 'Mellyphone@local', # Dad home
'253' => 'amyboodhram@local', # Amy
'264' => 'mmplas@local', # office
'263' => 'Andy_and_Melly@local', # Home
'265' => 'AdeshOffice@local', # adesh
'270' => '00115922271360@voipbusterpro',
'273' => 'donna123@local', # Donna Dos Santos
'275' => '5926243120@Nygames', # Donna Cell
'274' => '00115926835784@powervoip', # Ignatius cell
'277' => '2271360@Nygames', # Donna Home
'712' => '*#2 454-1234', # San Jose Voice Mail, dial my SJ GV using SFO GV acnt
'713' => '*#1 (415) 335-1234', # San Francisco Voice Mail, dial my SFO GV using SJ GV acnt
'714' => '*#1 (773) 778-1234', # San Francisco Voice Mail, dial my Chicago GV using SJ GV acnt
'411' => '(800) 466-4411', # Google's Directory Assistance, GOOG-411
'200' => '303@sip.blueface.ie&612@fwd.pulver.com',
'300' => '441923287748@Voxalot', # BT speaking clock
'666' => '4153767253@podlinez.net', # CNN Headlines (266 = "CNN")
'677' => '8186882773@podlinez.net', # NPR's most e-mailed stories (677 ="NPR")
'742' => '6506441934@podlinez.net', # Prairie Home Companion's, or PHC's
# News from Lake Wobegon (742 = "PHC")
'932' => '7755333366', # Columbus OH-based national weather (932 = "WEA[ther]")
}
# CNAM table: number in ENUM format => caller's name
CNAM = {
'(212) 555-1212' => 'Dear mom',
'(240) 418-3987' => 'Aunty Tina',
'(718) 908-2828' => 'Ali infinity',
'(718) 656-1001' => 'Michelle Gomez Work',
'(443) 850-7625' => 'Aunty Ann Aponte',
'(864) 502-8863' => 'Daddy',
'(347) 857-9902' => 'Aunty Donna Guyana',
'(347) 441-0605' => 'Amy and Richard',
'(347) 561-4880' => 'Michelle Gomez Home',
'(443) 739-9497' => 'Diana Pinky Ramlal cell',
'(315) 895-1479' => 'Hey people Wake Up it is Six AM',
'(646) 573-2819' => 'Michelle Gomez Cell',
'(718) 502-8863' => 'Andy and Melly',
'(718) 879-8933' => 'Vijay Home',
'(347) 210-6631' => 'Vijay Cell',
'(917) 443-2170' => 'Nishal Ramnarine',
'(754) 245-3916' => 'Rachael Diaz',
'(213) 884-6354' => 'Tangir Alam',
'(215) 333-2211' => 'Bratty kid',
}
# Uncomment next line and insert your White Pages API key, if you have it
# WP_key = '702f53d569ee0dfgasdfggsdfgs62fe72fc' # White Pages API key
# Uncomment line below to enable misdialing safeguards
# EnableSafeguards = 1
# Excluded Prefixes. Provides a safeguard against accidentally calling premium numbers
ExcludedPrefixes = [
' 1 (900 | 809)', # USA Premium
' 1 \d\d\d 555 1212', # USA Directory assistance
'44 (9 | 55 | 70 | 84 | 87)', # UK Premium
'49 (1 [^567] | 900)', # Germany Premium
'39 (1 | 84 | 89)', # Italy Premium
'420 90', # Czech Premium
'32 (70 | 90\d)', # Belgium Premium
]
# Yet another safeguard, list of blessed country codes
Allowed_Country = %w{
1 33 36 37[0-2] 380 39 41 420 44 49 61 7 86 883 886 90 972 998
}
# My own ENUM database
MyENUM = {
'+1 (408) 334-1234' => 'brother@local', # Brother George
}
# Enum database list
EnumDB = [
MyENUM, # look in MyENUM first
'e164.org',
'e164.info',
'e164.arpa',
'e164.televolution.net',
'enum.org',
]
# Serviced domains, must be in lowercase!
Domains = ['sipsorcery.com','sip.sipsorcery.com','sip1.sipsorcery.com','sip2.sipsorcery.com','69.59.142.213']
Host = 'sipsorcery.com' # Replaces "host" on incoming calls
# Google Voice accounts
GoogleVoice = GV.new '#2', nil, 'Google Voice', :usr => 'gdfgdfdfgb', :pwd => 'fgdfbgsdfbgs',
:cb => '(305) 760-4525', :match => '7185028863'
PSTN = VSP.new '#1', '${EXTEN:1}@pstn', 'SPA3102 at home'
nygames = VSP.new '#3', ' ${dst:6}@nygames', 'Vijay'
# ******************** s e l e c t V S P *******************************
def selectVSP # VoIP provider selection
case @num
when /(^1([2-9]\d\d)[2-9]\d{6})/ # North America
@num = $1 # Truncate to 11 digits
case $2 # check area code
when "868" # Trinidad
route_to PSTN, "Trinidad & Tobago"
else
route_to GoogleVoice, 'USA/Can' # all other destinations within US & Canada
end
when /^592\d{10}$/ # Guyana
route_to nygames, "Guyana"
when /^86/ # China
route_to PowerVOIP, 'China'
else
rejectCall(603,"Number's too short, check & dial again") if @num.length < 9
route_to nygames
end
end
# ------------ O P T I O N A L C O N F I G U R A T I O N --------------- #
# ******************** i n c o m i n g C a l l *************************
BlackList = [
'8009359935',
]
def incomingCall
sys.SetFromHeader(formatNum(@cname || @cid,true), nil, Host) # Set FromName & FromHost for sys.Dial
# Forward call to the bindings (ATA / softphone)
# Change FromURI when forwarding to @local, or else Bria won't find contact in its phonebook!
callswitch("#{@user}@local[fu=#{@cid}]",45) unless (2330..2231) === @t.hour*100 + @t.min # reject incoming calls from 11:30p to 11:31p
@code, @reason = 480, "#{@user} is asleep" unless @code # if nothing else, must be the night hour
@code = 486 if @trunk =~ /IPCOMM/i ## *** temporary fix for IPCOMMS ***
case req.Header.from.FromURI.User.to_s
when / ( 8009359935 ) / then sys.Respond(403, "Forbidden") # No Country code ( 7041234567 )
end
end
# ************************** t o E N U M *******************************
def to_ENUM num
num.gsub!(/[^0-9*+]/,'') # Delete all fancy chars (only digits, '+' and '*' allowed)
# Check if the number begins with one of international prefixes:
# '+' - international format
# 00 - European style international prefix (00)
# 011 - US style international prefix (011)
num =~ /^(\+|00|011)/ and return $' # if yes, remove prefix and return
case num # Special cases
when /^[2-9]\d{6}$/ # Local call, 7-digit number
'1' + Area + num # prefix it with country and area code
when /^[01]?([2-9]\d{9})/ # US number with or without "1" country code
'1' + $1 # add country code and truncate number to 10-digit
when /^\*/ # Voxalot voicemail, echotest & other special numbers
num # ... as is
else
rejectCall(603,"Wrong number: '#{num}', check & dial again")
end
end
# ****** E N D O F C O N F I G U R A T I O N S E C T I O N ******** #
# ************************** C A L L S W I T C H **********************
def callswitch(num,*args)
@timeout = args[0]
num.gsub!(/%([0-9A-F]{2})/) {$1.to_i(16).chr} # Convert %hh into ASCII
@num = Speeddial[num] || num # If there is speed dial entry for it...
if @num =~ /@/ # If we already have URI, just dial and return
sys.Log("URI dialing: #@num")
dial(@num,*args)
else # Not URI
rexp = VSP.tab.keys.sort {|a,b| b.length <=> a.length}.map {|x| Regexp.escape(x)}.join('|')
if @num =~ /^(#{rexp})/ # If number starts with VSP selection prefix
@num = $'; @forcedRoute = VSP.tab[$1]
@noSafeGuards = (@forcedRoute.fmt =~ /Disable\s*Safe\s*Guards/i)
end
@num = to_ENUM(@num) # Convert to ENUM
rejectCall(503,"Number's empty") if @num.empty?
sys.Log("Number in ENUM format: #{@num}")
if @forcedRoute && !@noSafeGuards
route_to @forcedRoute, "Forced routing!", false # if forced with prefix, skip ENUM, safeguards & VSP selection
else
checkNum if defined?(EnableSafeguards) && !@noSafeGuards
selectVSP # Pick appropriate provider for the call
end
end # URI
end
# *************************** R O U T E _ T O ****************************
def route_to vsp, dest=nil, enum = EnumDB
enum.to_a.each do |db| # if enum enabled, look in all enum databases
if uri = (db.class == Hash)? db[@num] : sys.ENUMLookup("#{@num}.#{db}")
sys.Log("ENUM entry found: '#{uri}' in #{db.class == Hash ? 'local' : db} database")
dial(uri)
end
end # ENUM not found or failed, call via regular VSP
return unless vsp # No VSP - do nothing
uri = vsp.fmt.gsub(/\s+/,'').gsub(/\$\{EXTEN(:([^:}]+)(:([^}]+))?)?\}/) {@num[$2.to_i,$4? $4.to_i : 100]}
dest &&= " (#{dest})"; with = vsp.name; with &&= " with #{with}"
sys.Log("Calling #{formatNum(@num)}#{dest}#{with}")
if vsp.is_gv?
vsp.repeat.times do |i|
@code, @reason = 200, "OK" # assume OK
sys.GoogleVoiceCall *vsp.getparams(uri, i + (vsp.rand ? @t.to_i : 0))
sys.Log("Google Voice Call failed!")
@code, @reason = 603, 'Service Unavailable'
end
else
vsp.repeat.times do
dial(uri, @timeout || vsp.tmo || 300) # Dial, global time-out overrides account
end
end
end
# ******************************* D I A L ********************************
def dial *args
@code, @reason = nil
sys.Dial *args # dial URI
status() # We shouldn't be here! Get error code...
sys.Log("Call failed: code #{@code}, #{@reason}")
end
# ***************************** S T A T U S ******************************
def status
begin
@code, @reason = 487, 'Cancelled by Sipsorcery'
sys.LastDialled.each do |ptr|
if ptr
ptr = ptr.TransactionFinalResponse
@code = ptr.StatusCode; @reason = ptr.ReasonPhrase; break if @code == 200
# sys.Log("#{ptr.ToString()}")
end
end
rescue
end
end
# ************************ r e j e c t C a l l ***************************
def rejectCall code, reason
@code = code; @reason = reason
sys.Respond code, reason
end
# **************************** C H E C K N U M **************************
def checkNum
return if @num.match(/^\D/) # skip if number doesn't begin with a digit
# Reject calls to not blessed countries and premium numbers
# (unless VSP was forced using #n dial prefix)
rejectCall(503,"Calls to code #{formatNum(@num).split(' ')[0]} not allowed") \
unless @num.match "^(#{Allowed_Country.join('|')})"
rejectCall(503,"Calls to '#{formatNum($&)}' not allowed") if @num.match \
'^(' + ExcludedPrefixes.map { |x| "(:?#{x.gsub(/\s*/,'')})" }.join('|') + ')'
end
# ********************** k e y s t o E N U M *************************
def keys_to_ENUM (table)
Hash[*table.keys.map! {|key| to_ENUM(key.dup)}.zip(table.values).flatten]
end
# ************************** g e t T I M E *******************************
def getTime
Time.now + ((Tz+7)*60*60) # Get current time and adjust to local. SS Server is in GMT-8
end
# ******************************* M A I N ********************************
begin
sys.Log("** Call from #{req.Header.From} to #{req.URI.User} **")
sys.ExtendScriptTimeout(15) # preventing long running dialscript time-out
@t = getTime()
sys.Log(@t.strftime('Local time: %c'))
EnumDB.map! {|x| x.class == Hash ? keys_to_ENUM(x) : x } # rebuild local ENUM table
if sys.In # If incoming call...
@cid = req.Header.from.FromURI.User.to_s # Get caller ID
# Prepend 10-digit numbers with "1" (US country code) and remove int'l prefix (if present)
@cid = ('1' + @cid) if @cid =~ /^[2-9]\d\d[2-9]\d{6}$/
@cid.sub!(/^(\+|00|011)/,'') # Remove international prefixes, if any
prs = req.URI.User.split('.') # parse User into chunks
@trunk = prs[-2] # get trunk name
@user = prs[-1] # called user name
# Check CNAM first. If not found and US number, try to lookup caller's name in Whitepages
if !(@cname = keys_to_ENUM(CNAM)[@cid]) && @cid =~ /^1([2-9]\d\d[2-9]\d{6})$/ && defined?(WP_key)
url = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20xml%20where%20url%3D'http%3A%2F%2Fapi.whitepages.com%2Freverse_phone%2F1.0%2F%3Fphone%3D#{$1}%3Bapi_key%3D#{WP_key}'%20and%20itemPath%3D'wp.listings.listing'&format=json"
if js = sys.WebGet(url,4).to_s
@cname, dname, city, state = %w(businessname displayname city state).map {|x| js =~ /"#{x}":"([^"]+)"/; $1}
@cname ||= dname; @cname ||= "#{city}, #{state}" if city && state
end
end
sys.Log("Caller's number: '#{@cid}'"); sys.Log("Caller's name: '#{@cname}'") if @cname
incomingCall() # forward incoming call
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.include?(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
strange why the call does not reach ext Andy_and_Melly@sipsorcery.com