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

Getting started with the SIP Sorcery
Post Reply
rnio
Posts: 63
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: 63
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

Who is online

Users browsing this forum: No registered users and 1 guest