A NEW Dialplan ... check it out :) PART #1 of 2

Getting started with the SIP Sorcery
Post Reply
rnio
Posts: 89
Joined: Tue Jul 03, 2012 4:56 pm

A NEW Dialplan ... check it out :) PART #1 of 2

Post by rnio » Mon Mar 03, 2014 1:41 pm

*************************
*** PART #1 of 2***
************************

Hi There,

ever since I discovered sipsorcery ... I love the things I can do.

Here is a dialplan I want to share and hope that others can use it too or at least get inspired by it.

Robert

PS: Just make sure you do NOT use the Silverlight interface, when putting it in ... the plan is just too BIG :)

Have Fun:

### I had to SPLIT the post into TWO parts, because ... its bigger than the max allowed

Code: Select all

#Ruby

###############################################################################################################
###############################################################################################################
###############################################################################################################
###############################################################################################################
#																											  #
#									ATTENTION																  #
#																											  #
#						This dial plan is TOO BIG / LONG 													  #
#																											  #
#						===> You can ONLY enter / edit it in the "normal" web interface.					  #
#																											  #
#						it does NOT WORK with the SILVERLIGHT interface										  #
#																											  #
#						This has NOTHING to do with the execution / performance its just "cosmetics"		  #
#																											  #
###############################################################################################################
###############################################################################################################
###############################################################################################################

# Copyright 2011 - 2014 Robert Nio
# Copyright 2010 Mike Telis, Mike Green, and Steven Jackson
# 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.

# Script is based on a script originally posted by Mike Telis

###############################################################################################################
###############################################################################################################
###############################################################################################################
# FEATURES of this dialplan:
#
# Support making your ATA device a little more intelligent
# Support for E911 (link of VOIP number to physical address for emergency calls)
# Support for commercial and free CNAM service providers (match number to name)
# Support for PERSONAL CNAM directory (match numbers to names e.g. 123-4444 ==> Daddy)
# Support for PERSONAL ENUM database (ability to call extensions INTERNALY rather than to route the call through an outside sip-provider)
# Support to set custom Caller ID (PROVIDER must support this ... DIDLOGIC does)
# Support for RULES based on time in coming CLI etc.
# Support SIMPLE and COMPLEX speeddial numbers
# Support "E164" dialing format
# Support for various international prefixes (e.g. 00 | 011)
# Support various SIP-PROVIDERS incl. Google Voice
# Support for MANUAL & AUTOMATIC SIP-Provider selection (e.g. international call to provider A ... domestic calls to provider B)
# Support for Google Voice as a VOIP provider (dial-out)
# Support for simple Google Voicemail retrieval
# Support Call-Trunks (ability to call multiple lines simultaneously)
# Support for customize actions depending who is calling (e.g. forward to specific number when daddy calls)
# Support of misdialing safeguards (e.g. avoid expensive premium calls by accident)
# Support restricting the countries one can call
# Simplified LOGGING / DEBUGGING of your dialplan
# Provides extensive logging during dialplan execution
# Makes use of NICE number formatter from mike :)
# 
###############################################################################################################
###############################################################################################################
###############################################################################################################
###############################################################################################################
###############################################################################################################

###############################################################################################################
#
# We did INCULDE "mikesgem" in this script, because we needed to EXTEND the VSP definition with "intPrefix"
#
#require 'mikesgem'
#
###############################################################################################################
###############################################################################################################
###############################################################################################################
###############################################################################################################
###############################################################################################################
###############################################################################################################

class Hash; alias :+ :merge; end; Home,Mobile,Work,Gizmo = 1,2,3,7
# **** My classes. DO NOT EDIT from here ********************************* #
class VSP
  @vsptab = {}
  def self.tab; @vsptab; end
  attr_reader :fmt, :name, :repeat, :tmo, :intPrefix
  def initialize *args
    attrib = args.pop
    args << attrib and attrib = {} unless attrib.class == Hash
    @pfx, @fmt, @name = args
    attrib.empty? || %w{pfx name tmo intPrefix fmt repeat rand}.each do |attr|
      ivar = "@#{attr}"; val = attrib.delete(attr.to_sym)
      instance_variable_set(ivar,val) if val && !instance_variable_get(ivar)
    end
    @repeat ||= 1; @fmt ||= '+${EXTEN}' if is_gv?
    unless @pfx.to_s.empty?
      raise "Duplicated dial prefix '#{@pfx}'" if VSP.tab.has_key?(@pfx)
      VSP.tab[@pfx] = self
    end
    @attrib = attrib if is_gv?
  end
  def is_gv?; self.class == GV; end
end
 
class GV < VSP
  attr_reader :rand
  def getparams num, i=0
    acnt = @attrib[:account] || Array[@attrib]
    a = {:num => num, :tmo => @tmo || 10, :match => '.*'} # init with default values
    a.update(acnt[i % acnt.length])                       # add other params
    a[:cb].gsub!(/\D/,'')                                 # Delete all but digits
    a[:type] ||= (a[:cb] =~ /^1?111/) ? Gizmo : Home      # if no type, define it depending on area code "111"
    a.values_at(:usr, :pwd, :cb, :num, :match, :type, :tmo)
  end
end
 
def Provider(*args)
  a = args.last; a.class == Hash && (a[:usr] || a[:account]) ? GV.new(*args) : VSP.new(*args)
end
# **** .......................... to here ******************************** #
 
# *************************  f o r m a t N u m  ****************************
 
def formatNum(num,exact=false)
  case num
                   # Closed Numbering Plan
    when /^(39)(0[26]|0\d[0159]|0\d{3}|3\d\d)(\d*)(\d{4})$/,    # Italy: Milan, Rome, 0x0, 0x1, 0x5, 0x9, 4-digit
         /^(41|48)(\d{2})(\d{3})(\d{4})$/,       # Swiss, Poland
         /^(34)(9[1-9]|[5-9]\d\d)(\d{3})(\d{3,4})$/, # Spain
         /^(32)(4[789]\d|[89]0\d|[2-4]|[15-8]\d)(\d{3})(\d{3,4})$/, # Belgium
         /^(86)(1[2-9]\d)(\d{3,4})(\d{4})$/,     # China mobile
         /^(886)(37|49|89|\d)(\d*)(\d{4})$/,     # Taiwan
         /^(972)(\d{1,2})(\d{3})(\d{4})$/,       # Israel
         /^(31)(6|800|8\d|9\d\d)(\d*)(\d{4})$/   # Netherlands non-geo
      sep = $3[2] ? '-' : ''                     # separator if $3 group has 3 or more digits
      "+#$1 #$2 #$3#{sep}#$4"
 
                   # Open Numbering Plan
    when /^([17]|90)(\d{3})(\d{3})(\d{4})$/,     # USA, Russia, Turkey
         /^(61)(\d)(\d{4})(\d{4})/,              # Australia
         /^(49)(1[5-7]\d|30|40|69|89|\d\d1|\d{4})(\d*)(\d{4})$/, # Germany: (mobile|2dig|3dig|4dig) area
         /^(380|375|998)(\d{2})(\d{3})(\d{4})$/, # Ukraine, Belarus, Uzbekistan
         /^(370)(469|528|37|45|46|57|5|\d{3})(\d*)(\d{4})$/,    # Lithuania
         /^(36)(1|\d\d)(\d{3})(\d{3,4})$/,       # Hungary
         /^(86)(10|2\d|\d{3})(\d{3,4})(\d{4})$/, # China: Beijing, 2x, others 3-dig area code
         /^(91)(800|11|20|33|40|44|[789]\d|\d{3})(\d*)(\d{4})$/, # India
         /^(63)(2|[3-8]\d|9\d\d)(\d{3})(\d{4})$/, # Philippines (Manila, [3-8]x, 9xx - mobile)
         /^(81)(3|6|[2-9]0|\d\d0|\d\d)(\d*)(\d{4})$/, # Japan
         /^(55)(\d\d)(\d{4})(\d{4})$/,           # Brazil
         /^(31)(7\d|[1-5][035]|2[46]|3[68]|46|58|\d{3})(\d*)(\d{4})$/ # Netherlands geo
      sep = $3[2] ? '-' : ''                     # separator if $3 group has 3 or more digits
      "+#$1 (#$2) #$3#{sep}#$4"
 
    when /^(52)(1)?(33|55|81|\d{3})(\d*)(\d{4})$/ # Mexico
      "+#$1#{$2.nil? ? '' : ' ' + $2} #$3 #$4-#$5"
 
    when /^(33)(\d)(\d{2})(\d{2})(\d{2})(\d{2})$/ # France
      "+#$1 #$2 #$3 #$4 #$5 #$6"
 
    when /^(44)(11\d|1\d1|2\d|[389]\d\d)(\d{3,4})(\d{4})$/, # UK 2- and 3-digit area codes: 11x, 1x1, 2x, 3xx, 8xx, 9xx
         /^(44)(\d{4})(\d{3})(\d{3,4})$/        # UK 4-digit area codes
      "+#$1 (#$2) #$3 #$4"
 
    when /^(420)(\d{3})(\d{3})(\d{3})$/         # Czech Republic
      "+#$1 #$2 #$3 #$4"
 
    when /^(37[12])(\d{3,4})(\d{4})$/           # Latvia, Estonia
      "+#$1 #$2-#$3"
 
    when /^(373)([67]\d{2})(\d{2})(\d{3})$/     # Moldova mobile
      "+#$1 #$2-#$3-#$4"
 
    when /^(373)(22|\d{3})(\d{1,2})(\d{2})(\d{2})$/ # Moldova landline
      "+#$1 (#$2) #$3-#$4-#$5"
 
    when /^(1|2[07]|3[0-469]|4[^2]|5[1-8]|6[0-6]|7|8[1246]|9[0-58]|\d{3})/ # all country codes
      exact ? num : "+#$1 #$'"                  # the pattern used only if exact == false
 
    else num    # No match - skip formatting
  end
end

###############################################################################################################
###############################################################################################################
###############################################################################################################
###############################################################################################################
###############################################################################################################
###############################################################################################################
###############################################################################################################
# 
# Here I kept a copy of my credentials
#
#LP-HOME_NUMBER  = "**homenumber**"               # my 10-digit Localphone number (Home)           EMAIL: myemail@mail.com      / ACC#:  account_number / PIN: 1234 / SIP-ID: 1234   / SIP-PW: password 
#LP-NFB_NUMBER   = "**officenumber**"             # my 10-digit Localphone number (OFFICE)         EMAIL: myemail@mail.com		/ ACC#:  account_number / PIN: 1234 / SIP-ID: 1234   / SIP-PW: password  
#LP-EGRB_NUMBER  = "**shopnumber**"               # my 10-digit Localphone number (SHOP)           EMAIL: myemail@mail.com		/ ACC#:  account_number / PIN: 1234 / SIP-ID: 1234   / SIP-PW: password 
#SGDE_Nummer     = "**germannumber**"             # my 10-digit Sipgate number    (GERMANY)        EMAIL: myemail@mail.com      / ACC#:  account_number             / SIP-ID: 1234   / SIP-PW: password 
#
#Google_HOME     = "**homenumber**"				  # my 10-digit Google number     (Home)		   EMAIL: myemail@mail.com 	    / ACC#: myaccount@gmail.com		/ PW: password 
#Google_Office   = "**officenumber**"			  # my 10-digit Google number     (OFFICE)		   EMAIL: myemail@mail.com 	    / ACC#: myaccount@gmail.com		/ PW: password 
#Google_Shop     = "**shopnumber**"				  # my 10-digit Google number     (SHOP)		   EMAIL: myemail@mail.com 	    / ACC#: myaccount@gmail.com		/ PW: password 
#Google_FAX      = "**faxnumber**"				  # my 10-digit Google number     (OFFICE-FAX)	   EMAIL: myemail@mail.com 	    / ACC#: myaccount@gmail.com		/ PW: password 
#



####################################################################
####################################################################
####################################################################
# --------DIAL Plan for your SIP device (phone)--------------------#                     
####################################################################
####################################################################
####################################################################
#
# The typical CISCO / LINKSYS ATA device is smart enough to help us 
# PRE-process the dialed number.
#
# Here is a SAMPLE "Dial-Plan" for your ATA:
#
#
# L:20,							The total time we wait ("20" seconds) before we reject the dialing attempt.
# ( 
# | P9 <:**officenumber**>		After taking the phone off hook, a user has "9" seconds to begin dialing. If no digits are pressed we call the DEFAULT # "**officenumber**"
# | x							Allow single digit SPEEDDIAL
# | #x**xxS0 					This allows to select a Single-Digit-VSP "#x" and then use a SPEEDDIAL "**xx"; do NOT wait for more digits "S0"
# | #xS3 x. 					This allows to select a Single-Digit-VSP "#x"; we set the wait time between digits to THREE seconds "S3"; followed by the number to dial
# | ##x**xxS0 					This allows to select a Single-Digit-Google-Voice VSP "*#x" and then use a SPEEDDIAL "**xx"; do NOT wait for more digits "S0"
# | ##xS3 x.					This allows to select a Single-Digit-Google-Voice VSP "*#x"; we set the wait time between digits to THREE seconds "S3"; followed by the number to dial
# | ####**xxS0					Disable Safe Guards "####" and let me dial a SPECIAL SPEEDDIAL
# | ####S3 x.					Disable Safe Guards "####" and let me dial whatever I want !
# | #####x**xxS0				Disable Safe Guards "####" and This allows to select a Single-Digit-VSP "#x" and then use a SPEEDDIAL "**xx"; do NOT wait for more digits "S0"
# | #####xS3 x.					Disable Safe Guards "####" and This allows to select a Single-Digit-VSP "#x"; we set the wait time between digits to THREE seconds "S3"; followed by the number to dial
# | ######x**xxS0				Disable Safe Guards "####" and This allows to select a Single-Digit-Google-Voice VSP "*#x" and then use a SPEEDDIAL "**xx"; do NOT wait for more digits "S0"
# | ######xS3 x.				Disable Safe Guards "####" and This allows to select a Single-Digit-Google-Voice VSP "*#x"; we set the wait time between digits to THREE seconds "S3"; followed by the number to dial
# | **xxS1 						SPEEDDIAL Two-Digit "**xx" we set the wait time between digits to ONE second "S1"
# | **xxxS0 					SPEEDDIAL Three-Digit "**xxx" with a NO wait time "S0"
# | 1 [2-9]xx [2-9]xxxxxxS0		Recognize a standard us number starting with "1" (3-digit "[2-9]xx" area code and 7-digit number "[2-9]xxxxxx") with a NO wait time "S0"
# | <:1650> [2-9]xxxxxxS2 		Accept a 7-digit number "[2-9]xxxxxx" and prepend my local area code "<:1650>" and wait a little between digits "S2"
# | <:1> [2-9]xx[2-9]xxxxxxS0 	Accept a 10-digit number "[2-9]xx[2-9]xxxxxx" and prepend "1" to make it an 11-digit US number, and NO wait between digits "S0"  
# | 011 x. 						Allow INTERNATIONAL numbers starting with "011" followed by multiple digits "x."
# | 00 x.						Allow INTERNATIONAL numbers starting with "00" (European Style) followed by multiple digits "x."
# | 49 x.						Allow GERMAN numbers starting with "49" (dialing format is E164) followed by multiple digits "x."
# | 62 x.						Allow INDONESIA numbers starting with "62" (dialing format is E164) followed by multiple digits "x."
# | 972 x.						Allow ISRAEL numbers starting with "972" (dialing format is E164) followed by multiple digits "x."
# | 911S0 						Call immediately "911" and do NOT wait for more digits
# | 110S0 						Call immediately "110" (German POLICE Emergency number) and do NOT wait for more digits
# | 112S0 						Call immediately "112" (German FIRE / AMBULANCE Emergency number) and do NOT wait for more digits
# | 611S0 						Call immediately "611" (Service hot-line) and do NOT wait for more digits
# |<411:16505551212S0>			Substitute "411" with the Google-411 local number "16505551212" do NOT wait for more digits "S0"
# )
#
#
# Copy and past the following STRING into the DIALPLAN field of your device:
#
# L:20, ( P9 <:**officenumber**> | x | #x**xxS0 | #xS3 x. | ##x**xxS0 | ##xS3 x.| ####**xxS0 | ####S3 x. | #####x**xxS0 | #####xS3 x. | ######x**xxS0 | ######xS3 x. | **xxS1 | **xxxS0 | 1 [2-9]xx [2-9]xxxxxxS0  | <:1650> [2-9]xxxxxxS2 | <:1> [2-9]xx[2-9]xxxxxxS0 | 011 x. | 00 x. | 49 x. | 62 x. | 972 x. | 911S0 | 110S0 | 112S0 | 611S0 |<411:16505551212S0> )
#
#
# More details can be found here: http://www.cisco.com/en/US/docs/voice_ip_comm/csbpvs/spa9000/administration/guide/SPA9000_Voice_System_V6-1_AG_NC-WEB.pdf
#
#
####################################################################
####################################################################
####################################################################



####################################################################
####################################################################
####################################################################
# ******************************* Configuration *******************#
# This section is where you can change the behavior of all the     #
# functions. Change these according to your needs.				   #
# *****************************************************************#
####################################################################
####################################################################
####################################################################

# It is possible to define your own "local" area code for making SS to SS
# calls. Dialing any number preceded by the value define will route a call
# internally, instead of making a call to a PSTN. If you do not wish to use
# this feature, leave it blank.
Area            = '111'                                   # my area code, this will be added to 7-digit dialouts


# The Time Zone offset based from GMT. Ie., London is 0, Paris is +1,  New York 
# is -5 and Kolkata is +5:30.
#
# !NOTE: It does not account for Daylight Savings, as it depends per country 
# (and the server on which Sipsorcery is deployed)
# 
# If unsure, visit http://www.timeanddate.com/worldclock/difference.html
#
Tz              = -8                                      # my time zone (GMT format, e.g. Eastern = -5, Central = -6)


TimeToComplete = 45                                       # Time to complete the dial in seconds

CallRobbi      = "**mycellnumber**@DIDLOGIC"			  # Best way to find my cell (DIALTHROUGH) for calls from Germany

# Specifies the canonical / IP host name(s) of the local SS server. Used to
# determine if a call is SS to SS, or SS to PSTN/URI
# 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 / incoming calls will come with this host


# Uncomment next line and insert your White Pages API key, if you have it
#WP_key         = '**WP-KEY**'			# White Pages API key                  

#CNAM_User		= 'CNAM-USER'
#CNAM_key       = 'CNAM-KEY'			# CallerIDservice API key


####################################################################  
# *************** Google Voice Configuration Section **************#
####################################################################

HOMEaccount = [{ 
				 :usr => 'myemail'					  ,	     # Your GV login name, with our without @gmail.com
				 :pwd => 'password'                ,		 # Your GV password
				 :cb  => '+1 (333) 495-1111'			     # my 10-digit Google-Voice Number (myemail@gmail.com)
}]

OFFICEaccount = [{  
				 :usr => 'myemail'			         ,	     # Your GV login name, with our without @gmail.com
				 :pwd => 'password'                ,		 # Your GV password
				 :cb  => '+1 (333) 331-1111'				 # my 10-digit Google-Voice Number (myemail@gmail.com)
}]

SHOPaccount = [{ 
				 :usr => 'myemail'					 ,	     # Your GV login name, with our without @gmail.com
				 :pwd => 'password'                ,		 # Your GV password
				 :cb  => '+1 (333) 495-1111'				 # my 10-digit Google-Voice Number (myemail@gmail.com)
}]

TEST_HOMEaccount = [{ 
				 :usr => 'myemail'					 ,	     # Your GV login name, with our without @gmail.com
				 :pwd => 'password'                ,		 # Your GV password
				 :cb  => '+1 (333) 663-1111'			     # my 10-digit Google-Voice Number (myemail@gmail.com)
}]

TEST_OFFICEaccount = [{  
				 :usr => 'myemail'			         ,	     # Your GV login name, with our without @gmail.com
				 :pwd => 'password'                ,		 # Your GV password
				 :cb  => '+1 (333) 417-1111'				 # my 10-digit Google-Voice Number (myemail@gmail.com)
}]

TEST_SHOPaccount = [{ 
				 :usr => 'myemail'					  ,	     # Your GV login name, with our without @gmail.com
				 :pwd => 'password'                ,		 # Your GV password
				 :cb  => '+1 (333) 502-1111'				 # my 10-digit Google-Voice Number (myemail@gmail.com)
}]


####################################################################
# *************** SIP Provider Configuration Section **************#
####################################################################

Local_HOME   = VSP.new '#0' , '   ${EXTEN}@ Local-HOME'		,    'Localphone Home route'				, :tmo => 60 , :intPrefix => '00' 
Local_Office = VSP.new '#1' , '   ${EXTEN}@ Local-OFFICE'	,	 'Localphone Office route'				, :tmo => 60 , :intPrefix => '00' 
Local_Shop   = VSP.new '#2' , '   ${EXTEN}@ SSprovider-2'	,    'Localphone Shop route'				, :tmo => 60 , :intPrefix => '00' 
SG_Germany   = VSP.new '#3' , '   ${EXTEN}@ SG-Germany'		,    'SIPGate GERMANY route'				, :tmo => 60 , :intPrefix => '00' 
DIDLOGIC	 = VSP.new '#4' , '   ${EXTEN}@ DIDLOGIC'		,    'DIDLOGIC route'						, :tmo => 60 , :intPrefix => '' 

Google_HOME  = GV.new  '##0', nil                       ,    'Google Voice (myemail@gmail.com) route'	 ,    :account => HOMEaccount    , :repeat => 3, :rand => true, :tmo => 60 , :intPrefix => '011' 
Google_Office   = GV.new  '##1', nil                    ,    'Google Voice (myemail@gmail.com) route'    ,    :account => OFFICEaccount  , :repeat => 3, :rand => true, :tmo => 60 , :intPrefix => '011'
Google_Shop  = GV.new  '##2', nil                       ,    'Google Voice (myemail@gmail.com) route'    ,    :account => SHOPaccount    , :repeat => 3, :rand => true, :tmo => 60 , :intPrefix => '011'


               VSP.new '####' , 'DisableSafeGuards'     # Disable safeguards prefix is ####
 
####################################################################
####################################################################


####################################################################
# Here we will set the SPECIFICS for each phone location           #
# We use ONE script for all attached devices. Based on the NAME of #
# the dial plan we will adjust the local specifics.				   #
####################################################################


case sys.DialPlanName

		when "HOME"										# We use the DIALPLAN-Name to set the various variables for each SS-Account (you link a DIALPLAN with each SS-Account)
														# ONE plan for all acounts
			sys.Log("----- ENTERED HOME Script")

			E911_Number          = "911@911-HOME"		# "911-HOME" is a SS-Provider, which is (in my case) registered with Callcentric and using their E911 Service (mapping Street Address with phone number)
			Default_Route        = DIDLOGIC				# "DIDLOGIC" is a SS-Provider, which is (in my case) registered with DIDLOGIC (cheap calls)
			Backup_Route         = Local_HOME			# "Local_HOME" is a SS-Provider, which is (in my case) registered with Localphone (cheap calls)
			My_Number            = "**homenumber**"		# This is the Number which this Dialplan instance will be "representing" (Many of our numbers are HOSTED by Google ==> see voicemail pickup)
			My_Telefon           = "HOME-PHONE"			# "HOME-PHONE" is a SS-Account; this is used to REGISTER my ATA-device with SS
			GV_Mailbox			 = "##2" + My_Number	# Number to call Google Voice
			CLI_Name		     = My_Telefon			# This is the caller NAME used with DIDLOGIC (set in "sys.SetFromHeader")
			CLI_Number		     = My_Number			# This is the caller ID used with DIDLOGIC (set in "sys.SetFromHeader")
			VMaccess			 = "12223334444"		# This is one of the numbers your Google Voice account sends calls to; ONLY those are allowed to pickup voice mail ... you need to configure access on the phone tab of your GV account settings

		when "OFFICE"

			sys.Log("----- ENTERED OFFICE Script")

			E911_Number          = "911@911-OFFICE"
			Default_Route        = DIDLOGIC
			Backup_Route         = Local_Office
			My_Number            = "**officenumber**"
			My_Telefon           = "OFFICE-PHONE"
			GV_Mailbox			 = "##2" + My_Number	
			CLI_Name		     = My_Telefon
			CLI_Number		     = My_Number
			VMaccess			 = "12223334444"

		when "OFFICE-LSM"

			sys.Log("----- ENTERED OFFICE-LSM Script")

			E911_Number          = "911@911-LSM"
			Default_Route        = DIDLOGIC
			Backup_Route         = Local_Office
			My_Number            = "12223334444"
			My_Telefon           = "OFFICE-LSM"
			GV_Mailbox			 = "##2" + My_Number	
			CLI_Name		     = My_Telefon
			CLI_Number		     = My_Number
			VMaccess			 = "12223334444"

		when "SHOP" ####The Google NUMBER needs to be adjusted when transfer from RINGCENTRAL is done

			sys.Log("----- ENTERED SHOP Script")
				
			E911_Number          = "911@911-SHOP"
			Default_Route        = DIDLOGIC
			Backup_Route         = Local_Shop
			My_Number            = "**shopnumber**"
			My_Telefon           = "SHOP-PHONE"
			GV_Mailbox			 = "##1" + My_Number	
			CLI_Name		     = My_Telefon
			CLI_Number		     = My_Number
			VMaccess			 = "12223334444"

		when "HOME-TEST"

			sys.Log("----- ENTERED HOME-TEST Script")

			E911_Number          = "911@911-HOME"
			Default_Route        = DIDLOGIC
			Backup_Route         = Local_HOME
			My_Number            = "**homenumber**"
			My_Telefon           = "HOME-TEST"
			GV_Mailbox			 = "16316631218"	
			CLI_Name		     = My_Telefon
			CLI_Number		     = My_Number
			VMaccess			 = "12223334444"

		when "HOME-OFFICE"

			sys.Log("----- ENTERED HOME-OFFICE Script")

			E911_Number          = "911@911-HOME"
			Default_Route        = DIDLOGIC
			Backup_Route         = Local_Office
			My_Number            = "**officenumber**"
			My_Telefon           = "HOME-OFFICE"
			GV_Mailbox			 = "##2" + My_Number	
			CLI_Name		     = My_Telefon
			CLI_Number		     = My_Number
			VMaccess			 = "12223334444"

		when "HOME-SHOP" ####The Google NUMBER needs to be adjusted when transfer from RINGCENTRAL is done

			sys.Log("----- ENTERED HOME-SHOP Script")

			E911_Number          = "911@911-HOME"
			Default_Route        = DIDLOGIC
			Backup_Route         = Local_Shop
			My_Number            = "**shopnumber**"
			My_Telefon           = "HOME-SHOP"
			GV_Mailbox			 = "##1" + My_Number	
			CLI_Name		     = My_Telefon
			CLI_Number		     = My_Number
			VMaccess			 = "12223334444"

	else # Just in case we have an UNKNOWN dial plan,  we set the HOME-TEST setting

			sys.Log("----- ENTERED ***** BACKUP ***** Script")

			E911_Number          = "911@911-HOME"
			Default_Route        = DIDLOGIC
			Backup_Route         = Local_HOME
			My_Number            = "**homenumber**"
			My_Telefon           = "HOME-TEST"
			GV_Mailbox			 = "##2" + My_Number	
			CLI_Name		     = My_Telefon
			CLI_Number		     = My_Number
			VMaccess			 = "12223334444"

end


####################################################################
####################################################################
####################################################################
# ------ END MANDATORY ENTRIES SECTION-----------------------------# 
####################################################################
####################################################################
####################################################################


####################################################################
####################################################################
####################################################################
# --------BEGIN OPTIONAL ENTRIES SECTION---------------------------#                     
####################################################################
####################################################################
####################################################################

####################################################################
# --------BEGIN OPTIONAL SECTION FOR SPEED DIAL--------------------#                     
# Speed dial entries. Format: "short code" => "destination (POTS or SIP)"
  
Speeddial = {

   #'1'	  => '#### #1 +1 (111) 283-4444',  # Special Dial "NO-SAFEGUARD + Force-VSP + Number"

   #'1'	  => '**mycellnumber**@SSprovider-1 & **wifecellnumber**@SSprovider-2 | **homenumber**@SSprovider-3'        ,  # Example of a call to MULTIPLE SIP endpoints (numbers)

   '1'	  => '**mycell**'              ,  # @SSprovider-3&**homenumber**@SSprovider-1&12223334444@SSprovider-2|**mycellnumber**@SSprovider-2'        ,  # Robbi Cell  
   '3'	  => '**wifecell**'            ,  # 
   '4'	  => '**soncell**'             ,  # 
   
  '**888' => '1234569951@sip.tropo.com',   # International Dialtone
  '**777' => '1234563416@sip.tropo.com',   # TROPO Test
  
  '911'   => E911_Number                ,  # Dial 911 via Callcentric							(Location address is registered with them)
  '112'   => E911_Number                ,  # German Firefighter # ==> Dial 911 Callcentric		(Location address is registered with them)
  '110'   => E911_Number                ,  # German Police		# ==> Dial 911 via Callcentric	(Location address is registered with them)
  
  '**701' => 'skype@ippiskype'         ,   # SKYPE me
  '**999' => 'music@iptel.org'         ,   # MUSIC for testing

  '**411' => '+1 (800) 466-4411'       ,   # Google's Directory Assistance, GOOG-411  
  '**303' => '303@sip.blueface.ie'     ,   # Blueface speaking clock (Ireland time)
  '**266' => '4153767253@podlinez.com' ,   # CNN Headlines (266 = "CNN")
  '**222' => '8458266132@podlinez.com' ,   # ABC News - Nightline - Podcast	(222 = "ABC")       
  '**677' => '6505236819@podlinez.com' ,   # NPR: Hourly News Summary Podcast (677 ="NPR") 
  '**932' => '7755333366'              ,   # Columbus OH-based national weather (932 = "WEA[ther]")  
  
  # My OWN Speeddial Numbers from LOCALPHONE and DIRECT dial #

  '**41' => '+1 9544732123'            ,   # Amex
  '**11' => '+972 123444444'           ,   # grandma's CELL
 

}

# --------END OPTIONAL SPEED DIAL ENTRY SECTION--------------------#     
####################################################################

####################################################################
# --------BEGIN OPTIONAL SECTION FOR CNAM LIST---------------------#  
# CNAM table: number in ENUM format => caller's name (phonebook)

CNAM = {

	'19544732123'       =>  'Amex'      ,	
    '0097244444444'     =>  'Oma'       ,	
    

}

# --------END OPTIONAL SECTION FOR CNAM LIST-----------------------# 
#################################################################### 

####################################################################
# --------BEGIN OPTIONAL SECTION FOR ENUM LIST---------------------#  
# My own ENUM database
# This is used as a "shortcut" .... rather to dial using an outside SIP provider, 
# we just move the call to a registered phone on our sipsorcery ACCOUNT.
# Look here for more detail: http://en.wikipedia.org/wiki/Telephone_number_mapping

MyENUM = {
   
    '**homenumber**'       =>  'HOME-PHONE@local & HOME-TEST@local'              ,	# We dial TWO extensions at the same time
	'**officenumber**'     =>  'OFFICE-PHONE@local & HOME-OFFICE@local'          ,  # "local" means SS will look for your phone under SS-ACCOUNTS
    #'**shopnumber**'      =>  'SHOP-PHONE@local & HOME-SHOP@local'     

}

# Enum database list

EnumDB = [
  MyENUM,                             # look in MyENUM first
 'e164.org',
 'e164.info',
 'e164.arpa',
 'e164.televolution.net',
 'enum.org',
]

# --------END OPTIONAL SECTION FOR ENUM LIST-----------------------#  
####################################################################

####################################################################
# --------BEGIN OPTIONAL SECTION FOR WHO IS CALLING----------------#                     
# Caller entries. Format: "caller-id" => "action"
  
CallFrom = {
  
    #'**mycellnumber**'   => '**mycell**@SSprovider-1' ,         # If called from this number ==> forward to URI
    #'**mycellnumber**'   => 'test'                    ,         # If called from this number ==> forward to TEST
    #'**homenumber**'     => 'dialtone'                ,	     # If called from this number ==> give dialtone
    #'12223334444'        => 'tropotest'               ,         # When I call from my CELL ==> testing mode
    
    
}
# --------END OPTIONAL WHO IS CALLING ENTRY SECTION----------------#  
####################################################################  
  
####################################################################
# --------BEGIN OPTIONAL SECTION FOR SAFEGARDS---------------------#  

# Uncomment line below to enable misdialing safeguards
EnableSafeguards = 1

# Excluded Prefixes. Provides a safeguard against accidentally calling premium
# numbers. Accepts both strings and patterns, spaces ignored
  
ExcludedPrefixes = [
   ' 1 (900 | 976 | 809)',            # USA Premium
   ' 1 \d\d\d 555 1212',              # USA Directory assistance
   '44 (9 | 55 | 70 | 84 | 87)',      # UK Premium
   '44 84 (4|5)',                     # UK Local Premium
   '44 70',                           # UK Personal Premium
   '43 (8|9)',                        # Austria Premium
   '32 (7|90)',                       # Belgium Premium
   '420 90',                          # Czech 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 [^567] | 900)',             # Germany Premium
   '39 (1 | 84 | 89)',                # 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
]

# Yet another safeguard, list of blessed country codes

Allowed_Country = %w{  1 31 39 43 44 49 61 62 65 972 506 }

# --------END OPTIONAL SECTION FOR SAFEGARDS-----------------------#  
####################################################################

####################################################################
####################################################################
# These rules are NOT implemented yet
####################################################################
####################################################################
####################################################################
# Answer rules.
#
#   Syntax: "Rule"   => "Options"
#
#   Where (CaSe Senitive!):
#      Rule         * Times between which calls will be answered, OR
#                   * "unavailable" : the rule when the user is unavailable, OR
#                   * "default" : the default rule, for which none of the other rules match.
#      Options      * "decline" : to decline the call with this rule, OR
#                   * One or more numbers to call.
#
# Multiple numbers separated by a '&' sign will be called simultaneously. All #
# phones will ring, until one of them is answered.
#
# Example: "12:00-14:00" => "homephone@asip.com&mobilephone@asip.com"
#
# Multiple numbers separated by a '#' will be called in the order 
# listed. The numbers can be limited to a maximum "wait for answer" time by 
# adding a '!' sign followed by the amount of seconds (15 seconds is the 
# internal limit).
#
# Example: "12:00-14:00" => "homephone@asip.com!10#mobilephone@asip.com!10"
# This will call "homephone", ringing up to 10 seconds and if not answered will 
# proceed to call "mobilephone", also ringing for up to 10 seconds
#AnswerRules = {
#   "17:30-21:30"   =>   "mobilephone@asip.com&homephone@asip.com",
#   "21:30-23:00"   =>   "homephone@asip.com",
#   "23:00-6:00"   =>   "decline",
#   "6:00-17:30"   =>   "officephone@asip.com!10#homephone@asip.com!5",
#   "$unavailable"   =>   "mobilephone@asip.com",
#   "$default"      =>   "#{sys.Username}@local",
#   "18885551212"   =>   "*3callback1#callback2"
#}
####################################################################


####################################################################
####################################################################
####################################################################
# --------END OPTIONAL ENTRIES SECTION-----------------------------#                     
####################################################################
####################################################################
####################################################################




####################################################################
#******************************************************************#
#******************************************************************#
#**** 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 ****#
#******************************************************************#
#******************************************************************#
####################################################################




####################################################################
####################################################################
####################################################################
# --------BEGIN FUNCTIONS / PROCEDURES ----------------------------#                     
####################################################################
####################################################################
####################################################################


####################################################################
# ***************************  R O U T E _ T O  *******************#
####################################################################

def route_to vsp, dest=nil, enum = EnumDB
  
  sys.Log("----- ENTERED Route_To")

  @num.gsub!(/[^0-9*+]/,'')                                 # Delete all fancy chars (only digits, '+' and '*' allowed)

  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); break
      
    end
    
  end                                                       # ENUM not found or failed, call via regular VSP

  return unless vsp                                         # No VSP - do nothing
  
  prettyNum = @num

  ExcludedPrefixes.each {|p| p.gsub!(/\s*/,''); sys.Respond(503,"Calls to #{$1}* not allowed") if @num =~ Regexp.new("^(#{p})")}

  if @intCall then 
  
	@num = vsp.intPrefix + @num 
	
  end
  
  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(prettyNum)}#{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("--------------ERROR:  Google Voice Call failed!")
          @code, @reason = 603, 'Service Unavailable'
      
        end # Loop
    
      else
		
		# Only DIDLOGIC supports setting the CLI

		if vsp.intPrefix == "" then 
		
				sys.SetFromHeader(CLI_Name, CLI_Number, nil)

				sys.Log("-------------- CLI-Name #{CLI_Name}  /  CLI-Number #{CLI_Number}")

			else

				sys.SetFromHeader(nil, nil, nil)

				sys.Log("-------------- CLI-Name NIL /  CLI-Number NIL")

		end

		vsp.repeat.times do
    
          dial(uri, @timeout || vsp.tmo || 300)     # Dial, global time-out overrides account
      
        end # Loop
    
  end # Dialing via GV?
  
end
####################################################################
####################################################################


####################################################################
# ********************  s e l e c t   V S P  **********************#
####################################################################
 
def selectVSP                                                              # VoIP provider selection

sys.Log("----- ENTERED Select VSP with @num: #{@num}")
  
# 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 =~ Regexp.new("^(#{p})")}
  
	  case @num

			when My_Number	                                                # My Google Voice number, when its called we go to our voice mail.

				sys.Log("-------------- Route to VOICEMAIL") 
				sys.SetFromHeader(My_Telefon, VMaccess, nil)				# We set the FROM-HEADER to be one of the forwarding numbers within your GV setup (PHONE-Tab on GV-Setup page)
				sys.Log("-------------- URI call")							# That number (VMaccess) is configured to lead us to VoiceMail if we call the Google-Number (My_Telefon)
				sys.dial(My_Number + "@DIDLOGIC", TimeToComplete)			# ONLY DIDLOGIC allows me to set the caller-id

                sys.Log("--------------ERROR:  Route to VOICEMAIL failed")    
                status()                                                    # We shouldn't be here! Get error code...

                sys.Log("--------------ERROR:  Call failed: code #{@code}, #{@reason}")

                route(nil,nil)                                              # let the calling function know that we did have an error
      
            when /(^1([2-9]\d\d)[2-9]\d{6})/                                # North America
 
                @num = $1                                                   # Truncate to 11 digits
                case $2                                                     # check area code
					
					#############################################################################################
					### UN-COmment if you choose to use a "normal" VOIP provider
					#############################################################################################
					when "800", "866", "877", "888"                         # toll free numbers...
						sys.Log("-------------- Default Route to TOLLFREE") 
                        route_to Default_Route, "USA toll-free", nil        
                    else
						sys.Log("-------------- Default Route to US & Canada ") 
                        route_to Default_Route, 'Default US & Canada route' # all other destinations within US & Canada
					#############################################################################################
					

					#############################################################################################
					### UN-COmment if you choose to use Google Voice as your VOIP provider
					#############################################################################################
					# Google Voice settings
					#when "800", "866", "877", "888"								# toll free numbers...
					#	sys.Log("-------------- GoogleVoiceCall to TOLLFREE") 
					#   route_to VSP.tab[GV_Account], "USA toll-free", nil						
					#else
					#	sys.Log("-------------- GoogleVoiceCall to US & Canada ") 
					#   route_to VSP.tab[GV_Account], 'Default US & Canada route'				# all other destinations within US & Canada
					#############################################################################################
					
                end

				#############################################################################################
				### UN-COmment if you choose to use Google Voice as your VOIP provider
                #route_to Default_Route, 'Default Route', nil                # If GV call failed, try one more time with our Default_Route
				#############################################################################################
					
				route_to Backup_Route, 'Backup Route', nil				    # If MAIN call failed via Default_Route, try one more time with our Backup_Route

            when /^972/                                                     # Israel
            
                case $1                                                     # check area code
 
                    when /^(5|6)/ then                                      # Israel Mobile
                     
                            route_to Default_Route, 'Destination - Israel Mobile', nil
 
                    else                                                    # Israel Land
 
                            route_to Default_Route, 'Destination - Israel Land', nil
                             
                end

				route_to Backup_Route, 'Backup Route', nil				    # If MAIN call failed via Default_Route, try one more time with our Backup_Route
               
            when /^49/                                                      # Germany
            
                case $1                                                     # check area code
 
                    when /^(5|6)/ then                                      # Germany Mobile
                     
                            route_to Default_Route, 'Destination - Germany Mobile', nil
 
                    else                                                    # Germany Land
 
                            route_to Default_Route, 'Destination - Germany Land', nil
                             
                end

				route_to Backup_Route, 'Backup Route', nil				    # If MAIN call failed via Default_Route, try one more time with our Backup_Route
               
            else
            
                rejectCall(603,"Number's too short, check & dial again") if @num.length < 9
                route_to Default_Route, 'Default route applied', nil
              
      end
  
end

####################################################################
####################################################################


####################################################################
# ****************************  C H E C K   N U M *****************#
####################################################################

def checkNum

  @num.match(/^\D/) && return  # 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 this country not allowed") unless @num.match "^(#{Allowed_Country.join('|')})"
  rejectCall(503,"Calls to #$&* not allowed") if @num.match '^(' + ExcludedPrefixes.map { |x| "(:?#{x.gsub(/\s*/,'')})" }.join('|') + ')'
  
end  

####################################################################
####################################################################


####################################################################
# **************************  to_ENUM  ****************************#
####################################################################
  
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 /                          #/
          num                           # ... as is
          
        else
          rejectCall(603,"Wrong number: '#{num}', check & dial again")
          
    end
        
end # to_ENUM

####################################################################
####################################################################


####################################################################
# **************************  Logger  *******************************
####################################################################

# This simplifies the LOGGING / DEBUGGING of your dialplan

def l(lname,lwert)

    sys.log("*****Die VARIABLE #{lname} hat den WERT: #{lwert}")
    
end

####################################################################
####################################################################
Last edited by rnio on Mon Mar 03, 2014 1:44 pm, edited 1 time in total.

rnio
Posts: 89
Joined: Tue Jul 03, 2012 4:56 pm

A NEW Dialplan ... check it out :) PART #2 of 2

Post by rnio » Mon Mar 03, 2014 1:43 pm

*************************
*** PART #2 of 2***
************************

Hi There,

ever since I discovered sipsorcery ... I love the things I can do.

Here is a dialplan I want to share and hope that others can use it too or at least get inspired by it.

Robert

PS: Just make sure you do NOT use the Silverlight interface, when putting it in ... the plan is just too BIG :)

Have Fun:

### I had to SPLIT the post into TWO parts, because ... its bigger than the max allowed

Code: Select all


####################################################################
# ********************  i n c o m i n g   C a l l  ****************#
####################################################################

def incomingCall

	number = req.Header.from.FromURI.User.to_s                                      # get a copy of caller's number (Caller ID)

	number = ('1' + number) if number =~ /^[2-9]\d\d[2-9]\d{6}$/                    # Make it standard US number incl "1"
    number.sub!(/^(\+|00|011)/,'')                                                  # Remove international prefixes, if any
  
	sys.Log("----- ENTERED Incoming Call Procedure")
	 
	sys.SetFromHeader(formatNum(@cname || number), number, Host)                    # Set FromName & FromHost for sys.Dial

    #sys.SetFromHeader(@cname, nil, nil)                                            # Set FromName & FromHost for sys.Dial
        
    callAction = CallFrom[@cid]
        
    if req.Header.from.FromURI.User.to_s == '01723334444' then 
		
		callAction = CallRobbi														# Calls from Germany ==> to my cell (DIALTHROUGH)
		
		if callAction.include? "DIDLOGIC" then 
			sys.Log("-------------- DIDLOGIC Route ==> set CLI")
			sys.Log("-------------- Mutter called ==> Robbi Cell")
			sys.SetFromHeader("Oma", "01149692224444", nil)					    	# Does ONLY work with DIDLOGIC VOIP for outgoing calls with them
		end

	end
        
	if callAction == nil then callAction = "normal" end
    
	dialthrough = true
    dialthrough = false unless callAction.include? "@"
        
    if dialthrough == false
        
			if callAction =="dialtone"							                    # Check if DIALTHROUGH wanted?

						sys.Log("-------------- Go get DIALTONE")
						callswitch("**888", TimeToComplete)				                    # Give dial tone
			     
					elsif callAction =="test"                                               # Normal TESTING?
                            
						sys.Log("-------------- Go TEST")
						callswitch("**999", TimeToComplete)
               
					elsif callAction =="tropotest"                                          # TROPO testing?
				    
						sys.Log("-------------- Go to TROPO to test")
						callswitch("**999", TimeToComplete)
                
					elsif callAction =="normal"                                             # NORMAL call?
				    
						sys.Log("-------------- NORMAL call")
						
						if sys.IsAvailable(My_Telefon, "sipsorcery.com")	                # If my ATA is registered (Check if the SS-Account is live and registered)

								callswitch(My_Telefon+"@local", TimeToComplete)				# forward all incoming calls to my SS-Account which is linked with my device "@local"

							######################################################################################################################
							# We do NOT use this portion for managing availability (e.g. office hours etc.) or forward to voicemail
							# We have all numbers parked @ Google and they forward it to SS ... and if nobody picks up it goes to VoiceMail
							######################################################################################################################
							#
							#
							#	if (8..19) == @t.hour	then				                # Its office time 
							#
							#			callswitch(My_Telefon+"@local", TimeToComplete)		# forward all incoming calls to it
							#	
							#		else													# If it is too late forward calls to Google Voice Mail
							#
							#			sys.Log("-------------- Outside Office hours ==> send to Google Voice MAIL") 
							#	
							#			callswitch(GV_Mailbox, TimeToComplete)
							#			
							#			sys.Log("--------------ERROR:  Call to Google VOICEMAIL failed")    
							#			status()                                                    # We shouldn't be here! Get error code...
							#	
							#			sys.Log("--------------ERROR:  Call failed: code            #{@code}, #{@reason}")
							#
							#			route(nil,nil)                                              # let the calling function know that we did have an error
							#
							#	end
                            ######################################################################################################################
    	
							else # Telefon Kaputt ==> My Cell

								sys.Log("--------------ERROR: #{My_Telefon} is not online, forwarding call to Robbi's Cell ...")
								sys.Log("-------------- URI call")
								sys.dial(CallRobbi, TimeToComplete)
								status()                                                                          # We shouldn't be here! Get error code...
								sys.Log("--------------ERROR: Call failed: code #{@code}, #{@reason}")
								
						end # My_Telefon ONLINE ?
                        
					elsif callAction.include? "@"
					
						sys.Log("-------------- URI call")
						sys.dial(callAction, TimeToComplete)
						status()                                                                          # We shouldn't be here! Get error code...
						sys.Log("--------------ERROR: Call failed: code #{@code}, #{@reason}")
                        
				else # OK normal call in
                    
					sys.Log("--------------ERROR: We should NOT be here (callAction): #{callAction}")
                
					rejectCall(999,"We have a TELEFON Meltdown !") 
					
			end # Check callAction
                
		else # We got a DIALTHROUGH
            
			sys.dial(callAction, TimeToComplete)
			status()																	  # We shouldn't be here! Get error code...
			sys.Log("--------------ERROR: Call failed: code #{@code}, #{@reason}")
                
	end # check if DIALTHROUGH or not 

end # DEF incomingCall
        
####################################################################
####################################################################


#################################################################### 
# **************************  C A L L    S W I T C H  *************#
####################################################################

def callswitch(num,*args)

  @timeout = args[0]
  
  num.gsub!(/%(..)/) {$1.hex.chr}                                # Convert %hh into ASCII
  
  sys.Log("----- ENTERED Call Switch with num = #{num}")

  vspNumber = @Default_Route									 # We set the DEFAULT route
  
  num = Speeddial[num] || num                                    # If there is speed dial entry for it... We do this here to allow special speeddials e.g. "NO-SAFEGUARD + Force-VSP + Number (#### #1 **mycell**)"
  
  num.gsub!(/[^0-9+*#]/,'') unless num =~ /@/ 					 # Delete all FANCY chars; keep only NUMBERS , "+", "*", "#" except if we get a URI "...@..."
  
  if EnableSafeguards ==1										 # SafeGuards Enabled ?
	
			@noSafeGuards = false		

		else

			@noSafeGuards = true

  end

  @forcedRoute = false											 # Use default Route										
  
  if num.match(/^(####)/)										 # DisableSafeGuards ?
	
		sys.Log("-------------- Safeguard Disabled using '####'")
		@noSafeGuards = true
		num.sub!($1,"")
  
  end
  
  if num.match(/^(##\d)/)										 # If number starts with GV-VSP selection prefix
  
		sys.Log("-------------- We selected a Google Voice Route using '##' plus 1st digit after that")
		vspNumber = $1
		num.sub!($1,"")

	elsif num.match(/^(#\d)/)									 # If number starts with VSP selection prefix
  
		sys.Log("-------------- We selected a specific Route using '#' plus 1st digit after that")
		vspNumber = $1
		num.sub!($1,"")
    
  end
  
  @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
    
		if ((vspNumber != "") && (vspNumber != @Default_Route))   # Do we have a VSP selection prefix
        
            sys.Log("-------------- Forced Route")
			@forcedRoute = true
			
        end

		if @num =~ /^(\+1)|1/ then								 # US Number?

				sys.Log("-------------- Domestic Call")
				@intCall = false

			elsif @num =~ /^(\+|00|011|49|62|972)/				 # International Number ?

				sys.Log("-------------- International Call")
				@intCall = true 
				
		end
        @num = to_ENUM(@num)									 # Convert to ENUM
        
		rejectCall(503,"Number's empty") if @num.empty?

		if (@forcedRoute)

				route_to VSP.tab[vspNumber], "Forced routing!", false									# if forced with prefix, skip ENUM, safeguards & VSP selection
                
            elsif @noSafeGuards

				route_to VSP.tab[vspNumber], "NO SafeGuards ==> send to default route!", false			# if NO Safegurads we go ahead and dial direct without CheckNum

			elsif EnableSafeguards == 1 
			
				checkNum 
                
				selectVSP                                                                               # Pick appropriate provider for the call
                
			else

				selectVSP										                                        # Go ahead and dial without checking !

        end
    
  end # URI
  
end
####################################################################
####################################################################


####################################################################  
# *******************************  D I A L  ***********************#
####################################################################
  
def dial *args

  sys.Log("----- ENTERED Dial Procedure")

  @code, @reason = nil
  
  sys.Dial *args                                # dial URI
  
  status()                                      # We shouldn't be here! Get error code...
  
  sys.Log("--------------ERROR: Call failed: code #{@code}, #{@reason}")
  
end

####################################################################
####################################################################


####################################################################  
# *****************************  S T A T U S  *********************#
####################################################################
  
def status

    begin
    
        @code, @reason = 487, 'Cancelled by Sipsorcery' unless @code
        
        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 # Loop
        
        sys.Log("-------------- #{ptr.ToString()}")
        
        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 

####################################################################
####################################################################


####################################################################
# **********************  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+8)*60*60) # Get current time and adjust to local. SS Server is in GMT-8
  
end

####################################################################
####################################################################


####################################################################
# *************************  f o r m a t N u m  *******************#
####################################################################

def formatNum(num,exact=false)

  case num

        # Closed Numbering Plan
    when /^(380|375)(\d{2})(\d{3})(\d{4})$/,							   # Ukraine, Belarus
         /^(972|998)(\d{2})(\d{3})(\d{4})$/,							   # Israel, Uzbekistan
         /^(36)(\d)(\d{3})(\d{4})$/,									   # Hungary
		 /^(39)(0[26]|0\d[0159]|0\d{3}|3\d\d)(\d*)(\d{4})$/,               # Italy: Milan, Rome, 0x0, 0x1, 0x5, 0x9, 4-digit
         /^(41|48)(\d{2})(\d{3})(\d{4})$/,                                 # Swiss, Poland
         /^(31)(6|800|8\d|9\d\d)(\d*)(\d{4})$/                             # Netherlands non-geo
      sep = $3[2] ? '-' : ''                                               # separator if $3 group has 3 or more digits
      "+ #$1 #$2 #$3#{sep}#$4"

        # Open Numbering Plan
    when /^([17]|90)(\d{3})(\d{3})(\d{4})$/,                               # USA, Russia, Turkey
         /^(61)(\d)(\d{4})(\d{4})/,                                        # Australia
         /^(49)(1[5-7]\d|30|40|69|89|\d\d1|\d{4})(\d*)(\d{4})$/,           # Germany: (mobile|2dig|3dig|4dig) area
         /^(31)(7\d|[1-5][035]|2[46]|3[68]|46|58|\d{3})(\d*)(\d{4})$/      # Netherlands geo
      sep = $3[2] ? '-' : ''                                               # separator if $3 group has 3 or more digits
      "+ #$1 (#$2) #$3#{sep}#$4"

    when /^(52)(1)?(33|55|81|\d{3})(\d*)(\d{4})$/                          # Mexico
      "+ #$1#{$2.nil? ? '' : ' ' + $2} #$3 #$4-#$5"

    when /^(33)(\d)(\d{2})(\d{2})(\d{2})(\d{2})$/                          # France
      "+ #$1 #$2 #$3 #$4 #$5 #$6"

    when /^(44)(11\d|1\d1|2\d|[389]\d\d)(\d{3,4})(\d{4})$/,                # UK 2- and 3-digit area codes: 11x, 1x1, 2x, 3xx, 8xx, 9xx
         /^(44)(\d{4})(\d{3})(\d{3,4})$/                                   # UK 4-digit area codes
      "+ #$1 (#$2) #$3 #$4"

    when /^(420)(\d{3})(\d{3})(\d{3})$/                                    # Czech Republic
      "+ #$1 #$2 #$3 #$4"

    when /^(37[12])(\d{3,4})(\d{4})$/                                      # Latvia, Estonia
      "+ #$1 #$2-#$3"

    when /^(373)([67]\d{2})(\d{2})(\d{3})$/                                # Moldova mobile
      "+ #$1 #$2-#$3-#$4"

    when /^(373)(22|\d{3})(\d{1,2})(\d{2})(\d{2})$/                        # Moldova landline
      "+ #$1 (#$2) #$3-#$4-#$5"

    when /^(1|2[07]|3[0-469]|4[^2]|5[1-8]|6[0-6]|7|8[1246]|9[0-58]|\d{3})/ # all country codes
      exact ? num : "+ #$1 #$'"											   # the pattern used only if exact == false

    else num    # No match - skip formatting
    
  end
  
end

####################################################################
####################################################################


####################################################################
####################################################################
####################################################################  
# *******************************  M A I N  ***********************#
####################################################################
####################################################################
####################################################################

begin
	
		sys.Log("----- ENTERED Main")

        # SIP tracing : true or false
        sys.Trace = true

		prettyNum = req.URI.User.to_s
		prettyNum = req.URI.User.to_s unless prettyNum = prettyNum.gsub!(/%(..)/) {$1.hex.chr}  
		
        sys.Log("-------------- call from URI #{req.Header.From.FromURI.ToString()} to #{prettyNum}.")
        sys.Log("-------------- Call from HEADER #{req.Header.From} to #{prettyNum} **")

        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...
	
		sys.Log("-------------- Got an Incoming Call")

        @cid = req.Header.from.FromURI.User.to_s                    # get a copy of caller's number (Caller ID)

        # Prepend 10-digit numbers with "1" (US country code) and remove int'l prefix (if present)
        # Some DID send Caller ID without country code
  
        @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
		
		##############################################################################################################
		# This is the OLD process to query Whitepages API 1.0 ... this does not work any more
		##############################################################################################################
		##############################################################################################################
		# 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
        #    
        #        #sys.Log("-------------- Caller's js: '#{js}'")
        #    
        #        @cname, dname, city, state = %w(businessname displayname city state).map {|x| js =~ /"#{x}":"([^"]+)"/; $1}
        #        
        #        # ***** WE do not have an ACCOUNT with them *****
        #        #if !(@cname ||= dname) && defined?(CNAM_key)
        #        #
        #        #    url = "http://cnam.calleridservice.com/query?u=#{CNAM_User}&k=#{CNAM_Key}&t=html&n=#{@cid[1..-1]}"
        #        #
        #        #    @cname = sys.WebGet(url,4).to_s
        #        #  
        #        #end
        # 
        #        @cname ||= dname; @cname ||= "#{city}, #{state}" if city && state
        #        #@cname ||= "#{city}, #{state}" if city && state
        #   
        #    end
        #    
        #end
        ##############################################################################################################
		##############################################################################################################
		
        # Just COMERCIAL service:
		#
        #if !(@cname = keys_to_ENUM(CNAM)[@cid]) && @cid =~ /^1([2-9]\d\d[2-9]\d{6})$/ && defined?(CNAM_key)
		#
        #   url = "http://cnam.calleridservice.com/query?u=#{CNAM_User}&k=#{CNAM_Key}&t=html&n=#{$1}"
		#	
        #   @cname = sys.WebGet(url,4).to_s
		#
        #end
		
		incomingCall       # forward incoming call
        
####################################################################
####################################################################
    else  # Outbound call ...
  
  		sys.Log("-------------- Got an Outgoing 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.split(':')[0]                       # Convert to lowercase and delete optional ":port"
    
        num << '@' << reqHost unless Domains.include?(host)         # URI dialing unless host is in our domain list

		prettyNum = num
		prettyNum = prettyNum.gsub!(/%(..)/) {$1.hex.chr}
        
        sys.Log("-------------- Call to: #{prettyNum} from #{host} **")
    
        callswitch(num, TimeToComplete)
  
  end # Call IN or OUT?
  
  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

Post Reply