# Method error

**URL:** <https://www.ruby-forum.com/t/method-error/226074>\
**Category:** Ruby\
**Created:** [July 22, 2010, 12:16pm UTC](https://www.ruby-forum.com/t/method-error/226074 "2010-07-22T12:16:50Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![jochem](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/9dc877/32.png) [@jochem](https://www.ruby-forum.com/u/jochem)\
**Post date:** [July 22, 2010, 12:16pm UTC](https://www.ruby-forum.com/t/method-error/226074/1 "2010-07-22T12:16:50Z")

</div>

I use sipsorcery for my SIP-calls, which uses a ruby dialplan.

The dialplan i got from  
[My "One for All" Ruby plan \*\* Updated 08-Oct-08 - SIP Sorcery Community Forums](http://forum.sipsorcery.com/viewtopic.php?f=15&t=826) raises an exception  
when I make an outgoing call.

Unfortunately, my ruby knowledge is very limited. Can someone tell  
what’s wrong?

Exception:

DialPlan=\> \*\* Error: undefined method `fixupNumber’ for  
#TNumber:0x0000370

Thanks in advance.

ruby code:

```
#Ruby
# Original by MikeTelis

```

([http://www.mysipswitch.com/forum/viewtopic.php?t=706](http://www.mysipswitch.com/forum/viewtopic.php?t=706))  
#  
# Adapted by Mike Green as following:  
#

```
# ******************************* Configuration

```

* * *

```
# This section is where you can change the behavior of all the

```

functions.  
# Change these according to your needs.  
#

* * *

```
# Specifies the host name required to place a local (MSS to MSS)

```

call.  
#  
# LocalDomain = “[sip.mysipswitch.com](http://sip.mysipswitch.com)”  
LocalDomain = “[sip.mysipswitch.com](http://sip.mysipswitch.com)”

```
# Specifies the canonical / IP host name(s) of the local MSS server.

```

Used to  
# determine if a call is MSS to MSS, or MSS to PSTN/URI  
#  
# Domains = [LocalDomain, “213.200.94.182”]  
Domains = [LocalDomain, “213.200.94.182”]

```
# It is possible to define your own "local" area code for making MSS

```

to MSS  
# calls. Dialing any number preceeded 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.  
#  
# LocalAreaCode = “”  
LocalAreaCode = “026”

```
# Specifify if a 9 needs to be dialed to make a call outside of the

```

local  
# MSS work. If enabled, a call to 5551212 would be routed to  
5551212@(LocalDomain)  
# and a call to 95551212 would be routed to  
5551212@(a\_sip\_provider).  
#  
# This function cannot be combined with the LocalAreaCode option.  
#  
# DialNineOut = true  
DialNineOut = false

```
# Enabling this option forces the User ID to be used the caller ID

```

(if supported  
# by the provider).  
#  
# UserIDAsOutgoingCallerID = false  
UserIDAsOutgoingCallerID = false

```
# Your local country code. This is used to replace the leading 0.

```

For example,  
# a number dialied as 0203112233 in the Netherlands would be  
converted to  
# 31203112233 if MyCountryCode = “31”.  
#  
# For North America (Country Code 1), the number will be prepended  
to the  
# dialed number, unless it is already present. Ie., 2125551212 will  
become  
# 12125551212.  
#  
# Use MyCountryCode = “” if no conversion is desired.  
#  
# MyCountryCode = “”  
MyCountryCode = “31”

```
# 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 MySipSwitch is deployed)  
#  
# If unsure, visit

> **[Time Difference between a Location and the World](https://www.timeanddate.com/time/difference/)**
>
> Time differences between a city and time zones worldwide. What is the time difference between your location and New York, Berlin, and Tokyo?

#  
# MyTimeZone = “-5”  
# MyTimeZone = “+5:30”  
MyTimeZone = “+1”

```
# Specify whether ENUM lookup should be used as the preferred method

```

of calling.  
#  
# You can override this function by dialing the number with \*9  
#  
# UseENUM = false  
UseENUM = true

```
# Default Callback Number. This number will be used in case the

```

bridge/callback  
# option is used, but no 2nd number was dialed.  
#  
# If the entry is empty, the default will be “yourself”, as in  
# sip:removed\_email\_address@domain.invalid  
#  
# DefaultCallbackNumber = “”  
DefaultCallbackNumber = “”

```
# Specify how long one particular number should ring until the next

```

number in  
# the list is dialed.  
#  
# DefaultDelay = 10  
DefaultDelay = 10

```
# Speed Dial numbers.
#
# Syntax: "(number)" => "(actual number or URI)"
#
# NOTE: It is valid to use special functions in Speed Dial!
#
# Speeddial = { "0" => "removed_email_address@domain.invalid", "1" =>

```

“\*\*removed\_email\_address@domain.invalid” }  
Speeddial = {  
“9901” =\> “removed\_email\_address@domain.invalid”, # Echo test USA  
“9949” =\> “removed\_email\_address@domain.invalid”, # Echo test Germany  
“9944” =\> “sip:removed\_email\_address@domain.invalid”, # Call quality test UK  
“303” =\> “removed\_email\_address@domain.invalid”, # Calls speaking time @  
blueface  
“612” =\> “removed\_email\_address@domain.invalid” # Calls speaking time @ pulver  
}

```
# Providers table.
#
# Syntax: "Key" => "[Prefix]@Provider"
#
# Where:
# Key A single digit, 0 being the default.
# Prefix Optional prefix that needs to be added to the

```

dialed number.  
# Provider Provider by name, as listed in MySipSwitch  
configuration.  
#  
# You can override the provider by dialing a number with the prefix  
\*1 and then  
# the key. For example:  
#  
# \*1412125553456 dials 12125553456 using the provider at key 4  
#  
# VSPtable = { “0” =\> “@ provider1”, “1” =\> “@ provider2” }  
VSPtable = {  
“0” =\> “@12voip”, # default provider (prefix numbers with 00)  
“1” =\> “@budgetphone” # budgetphone  
}

```
# Provider rules.
#
# Syntax: "Rule" => "Provider"
#
# Where:
# Rule A regular expression (Regexp) to match against a

```

number  
# Provider Provider by key, as listed in VSPtable above  
#  
# NOTE: Use a double backslash for a single one!  
#  
# VSPRules { “^\*1” =\> “0”, “^\*2” =\> “1” }  
VSPRules = {  
“^#{MyCountryCode}|^0” =\> “0” # A national (local)  
number

# “^[1]800|866|877|888\d{7,7}$” =\> “4”, # North America Toll

Free numbers

# “^1[2-9]\d{9,9}$” =\> “2” # North America

```
}

# 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 seperated by a ‘&’ sign will be called  
simultaneously. All #  
# phones will ring, until one of them is answered.  
#  
# Example: “12:00-14:00” =\>  
“removed\_email\_address@domain.invalid&removed\_email\_address@domain.invalid”  
#  
# Multiple numbers seperated 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” =\>  
“removed\_email\_address@domain.invalid!10#removed\_email\_address@domain.invalid!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” =\> “removed\_email\_address@domain.invalid&removed\_email\_address@domain.invalid”,

# “21:30-23:00” =\> “removed\_email\_address@domain.invalid”,

# “23:00-6:00” =\> “decline”,

# “6:00-17:30” =\>

“removed\_email\_address@domain.invalid!10#removed\_email\_address@domain.invalid!5”,

# “$unavailable” =\> “removed\_email\_address@domain.invalid”,

```
   "$default" => "#{sys.Username}@local"

```

# “18885551212” =\> “\*3callback1#callback2”

```
}

# Excluded Prefixes. Provides a safeguard against accidentally

```

calling premium  
# numbers.  
#  
# Syntax: “(number)”  
#  
# Where:  
# (number) Any number(s) at the start of a dialed number  
#  
# The numbers need to start with the country code. You can also use  
this to  
# block entire numbers from being dialed. To override this function,  
dial the  
# number with \*2.  
#  
# \*219005553456 dials 19005553456, bypassing the safeguard  
#  
# ExcludedPrefixes = [“118118”, “411”, “1900”]  
ExcludedPrefixes = [  
“1900”, “1976”, # USA Premium  
“449”, “4455”, “44870”, “44871”, # UK Premium  
“44844”, “44845”, # UK Local Premium  
“4470”, # UK Personal Premium  
“438”, “439”, # Austria Premium  
“327”, “3290”, # Belgium Premium  
“451”, “45501”, “45502”, “45503”, # Denmark Premium (…)  
“45701”, “45702”, “4580”, “4590”, # Denmark Premium  
“337”, “339”, # France Premium  
“491”, “49900”, # Germany Premium  
“391”, “392”, “394”, “395”, # Italy Premium (…)  
“396”, “397”, “398”, “399”, # Italy Premium  
“3114”, “3163”, “3168”, “3169”, # Netherlands Premium (…)  
“318”, “319”, # Netherlands Premium  
“4839”, “4820”, “4870”, “4880”, # Poland Premium  
“46900”, “46939”, “46944”, # Sweden Premium  
“41900”, “41901”, “41906” # Switzerland Premium  
]

```
# ********************************** DEFINES

```

* * *

```
# For basic functionality of this plan, it should not be neccesary

```

to  
# edit the code below.  
#

* * *

```
# DO NOT CHANGE THE TWO LINES BELOW!
Sys = sys
Req = req

```

### 

```
def fixupNumber(aNumber)
   number = String.new(aNumber =~ /^(.+)@(.+)$/ ? $1.to_s : aNumber)
   host = $2.to_s.downcase
   port = host.sub!(/\:(\d+)/, "") ? $1 : ""

   if (host == "local")
      # It's a MSS user -> MSS user call
      number << "@" << LocalDomain

   elsif (host == "") or (Domains.find{|x| x.downcase == host})
      # It's a MSS user -> PSTN call, unless LocalAreaCode is

```

matched.  
# A LocalAreaCode is not valid if a 9 needs to be dialed for  
outgoing calls.

```
      if (!LocalAreaCode.empty?) and (!DialNineOut)
         # We have a LocalAreaCode, but we'll also check in case it

```

was  
# dialed with the country code (if specified)  
LACC = LocalAreaCode.gsub(/^0/, MyCountryCode)

```
         if number.sub!(/^#{LocalAreaCode}/,"") or

```

(number.sub!(/^#{LACC}/, “”) unless MyCountryCode.empty?)  
number \<\< “@” \<\< LocalDomain  
end  
elsif DialNineOut  
number \<\< “@” \<\< LocalDomain unless number.sub!(/^9/, “”)  
end

```
   else
      # It's a MSS -> URI call

      number << "@" << host
   end

   number << ":" << port unless port.empty?

   return number
end

```

### 

```
# TNumber class
#
# Container for each particular number, with a seperate handler
#
class TNumber
   attr_reader :number, :provider, :override, :enum, :useenum,

```

:timeout  
attr\_writer :number, :provider, :override, :enum, :useenum,  
:timeout

```
   def initialize(aNumber)
      @number = fixupNumber(aNumber)
# @number = Speeddial[@number] if (Speeddial[@number])

      @provider = ""
      @override = false # Used for overriding excluded prefixes
      @useenum = UseENUM
      @enum = "" # Initialize ENUM var

      @timeout = extractDialTimeout(@number)
   end

   # Prepares the number for dialing.
   #
   def prepare
      return 0,"" if is_URI?

      # sub! below removes prefixes:
      # '+' - international format
      # 00 - European style international prefix (00)
      # 011 - US style international prefix (011)
      # 810 - Russian style international prefix (810)

       unless @number.sub!(/^(\+|00|011|810)/,"")
         # Convert a national number to an international number
         case MyCountryCode
            # North America
            when "1"
               # Prepend a North American number with the country

```

code,  
# unless it already starts with the country code  
@number = MyCountryCode + @number if @number =~  
/^[^1]/

```
            # Russia (From MikeTelis' original code)
            when "7"
               case @number
                  when /^82\d{7,7}$/
                     @number = "7496" + @number[2..-1]
                  when /^8/
                     @number[0] = "7"
                  when /^[1-9]\d{6,6}$/
                     @number = "7495" + @number
               end

          else
            # Apply default rule (replace 0 with country code),

```

unless  
# MyCountryCode is not specified.

```
            @number.sub!(/^0/, MyCountryCode) unless

```

MyCountryCode.empty?

```
          end
        end

      # Check if we can override the prefix, and if not, see if it's

```

in  
# the list of exluded prefixes.  
if !@override and hasExludedPrefix = ExcludedPrefixes.find  
{|prefix| @number =~ /^#{prefix}/ }  
return 403,“Numbers starting with #{hasExludedPrefix} are  
not permitted”  
end

```
        # If the provider was not specified by the user, we will

```

decide it here  
if @provider.empty?  
getEnum if @useenum  
selectProvider  
end

```
        return 0,""
   end

   # Selects the provider based on the number.
   #
   def selectProvider
      # Fix North American numbers that are longer than usual
      @number = $1 if @number =~ /(^1([2-9]\d\d)\d{7,7})/

        @provider = "0" # Set the default provider first

      VSPRules.each { |aRule|
         if @number =~ /#{aRule[0]}/
            @provider = aRule[1]
            break
         end
      }
   end

   # Extracts the timeout specified with the number
   def extractDialTimeout(aNumber)
      return aNumber.sub!(/\!(\d{1,2})/, '') ? $1.to_i : 0
   end

   # Are we using the ENUM to call?
   #
   def use_ENUM?
      return !@enum.to_s.empty?
   end

   # Is it a full URI instead of a number?
   #
   def is_URI?
      return @number =~ /@/
   end

   # Expands the number based on the providers' template, to be used
   # in Sys.Dial
   #
   def expandNumber
      if tpl = VSPtable[@provider]
         return tpl.sub(/\s*@\s*/) {|x| @number+"@"}
      else
         return @number
      end
   end

   # Sets the enum variable, if an ENUM is available
   #
   def getEnum
      Sys.Log("Attempting to retrieve ENUM for #{@number}")
      @enum = "" unless @enum =

```

Sys.ENUMLookup(“+#{@number}.e164.org”).to\_s  
Sys.Log(“Result ENUM lookup: ‘#{@enum}’”)  
end

```
   private :getEnum
end

# TDialList class
#
# Controls the numbers and call methods
#
class TDialList
   attr_reader :bridgenumbers

   MaxItems = 10

   def initialize
      @numbers = Array.new

      @bridgenumbers = false
   end

   # Add a number to the list
   #
   def append(aNumber)
      return 500,"Exceeded limit or class error" if (@numbers.length

```

== MaxItems) or (aNumber.class.name != “TNumber”)

```
      if !aNumber.is_URI?
         Code,Reason = processSpecialFunctions(aNumber)
         return Code,Reason if Code > 0
      end

      @numbers.push(aNumber)

      return aNumber.prepare
   end

   # How many numbers do we have?
   #
   def length
      @numbers.length
   end

   def deleteFirst
      @numbers.shift
   end

   def deleteLast
      @numbers.pop
   end

   # Access to the numbers, by index (key) or phone number
   #
   def [](key)
      return @numbers[key] if key.kind_of?(Integer)
      return @numbers.find { |aNumber| key == aNumber.number }
   end

   # Handles any special function present in the number
   #
   # Special Functions:
   #
   # *1(key) Override the provider with the one specified in

```

(key)  
# \*2 Bypass premium number safeguard  
# \*3 Bridge (callback) the numbers  
# \*9 Override ENUM setting (enable if disabled, and  
vice versa)  
# \*0 Trace the phone call  
# \*\* Dial a \*  
#  
def processSpecialFunctions(aNumber)  
while aNumber.number.sub!(/^\*([^\*])/, “”)  
case $1  
# Special function 1 - Override provider  
when “1”  
aNumber.number.sub!(/^(.)/, “”)  
aNumber.provider = $1;

```
                return 400,"Invalid provider selected #{$1}" if

```

VSPtable[aNumber.provider].to\_s.empty?

```
                Sys.Log("! Overriding service provider for

```

#{aNumber.number} to #{aNumber.provider}, template  
#{VSPtable[aNumber.provider]}")

```
            # Special function 2 - Bypass safeguard
            when "2"
               Sys.Log("! Bypassing premium number safeguard for

```

#{aNumber.number}")  
aNumber.override = true

```
            # Special function 3 - Bridge the numbers in the list

```

(will take only first two)  
when “3”  
Sys.Log(“! Request to bridge #{aNumber.number}”)  
@bridgenumbers = true

```
            # Special function 0 - Trace this particular call
            when "0"
               Sys.Log("! Requested a trace for this call.")
               Sys.Trace = true

            # Special function 9 - Override the use of ENUM
            when "9"
               Sys.Log("! Override use of ENUM")
               aNumber.useenum = !aNumber.useenum

            # Unknown function
            else
               Sys.Log("! Unknown function in dial sequence found:

```

#{$1} - Ignoring")  
end  
end

```
       # A double ** gets treated as a single * to dial
       aNumber.number.sub!(/^\*/,"")

       return 0,""
   end

   # Make the call
   #
   def dial(*args)
      if Sys.Out and UserIDAsOutgoingCallerID
         Req.Header.From.FromName =

```

Req.Header.From.FromURI.User.to\_s  
end

```
      if @bridgenumbers
         # If no default callback number is set, use local user
         DefaultCallbackNumber = "#{Sys.Username}@local" if

```

DefaultCallbackNumber.empty?

```
         number1 = @numbers[0].use_ENUM? ? @numbers[0].enum :

```

@numbers[0].expandNumber  
number2 = (length \< 2) ? DefaultCallbackNumber :  
@numbers[1].use\_ENUM? ? @numbers[1].enum : @numbers[1].expandNumber

```
         Sys.Log("* Initiating bridge between #{number2} and

```

#{number1}")  
Sys.Callback(number2, number1, 3) # 3 seconds before  
dialing  
else  
# If there’s more than one number in the list, try each one  
until  
# one is picked up. (No ring timeout for single number)

```
         ringtimeout = 0
         @numbers.each { |n|
               numbertd = n.use_ENUM? ? n.enum : n.expandNumber

               # If there's more than 1 number to call, set the

```

timeout if present.  
ringtimeout = n.timeout == 0 ? DefaultDelay :  
n.timeout if (length \> 1)

```
               if ringtimeout == 0
                  Sys.Log("* Dialing #{numbertd}")
                  Sys.Dial(numbertd)
               else
                  Sys.Log("* Dialing #{numbertd} with timeout

```

#{ringtimeout}")  
Sys.Dial(numbertd, ringtimeout)  
end  
}  
end

```
      return status
   end

   # Grab the status from the LastDialied list (Another great piece

```

by MikeTelis)  
#  
def status(li=0)  
if (ptr = Sys.LastDialled[li]).nil?  
return 487,“Cancelled by MSS”  
else  
ptr = ptr.TransactionFinalResponse # SIPTransaction &  
SIPResponse  
return ptr.StatusCode,ptr.ReasonPhrase  
end

```
      return 0,""
     end
end

# Inbound Call Manager. Uses a rule-based table to determine where
# an incomming call should be routed to, based on time of day and
# availability.
#
class TInboundMgr
   attr_reader :time

   @@localuser = "#{Sys.Username}@local"

   def initialize
      @time = Time.now.gmtime # In case this SIP Switch is

```

deployed outside Dublin

```
      # Some timezones have half hour and 45 minute differences.

```

Account for this.  
# It does NOT account for daylight savings!  
mtz = MyTimeZone.split(“:”)  
mtz[0] = ‘0’ if mtz[0].to\_s.empty?

```
      @time += mtz[0].to_i * 3600
      @time += mtz[0][0].chr == "-" ? ("-#{mtz[1]}".to_i * 60) :

```

(mtz[1].to\_i \* 60) unless mtz[1].to\_s.empty?

```
      Sys.Log("Using #{@time} to determine Answer Rule")

      callerid_name = Req.Header.From.FromName.to_s

      # Some SIPs simply leave the name blank, which some softphones

```

don’t  
# appreciate  
callerid\_name = Req.Header.from.FromURI.User.to\_s if  
callerid\_name =~ /^$|\D/

```
      # Replace any characters other than A..Z or numbers. This

```

could happen  
# with SIPBroker for instance ("Calgary,AB  
sip:removed\_email\_address@domain.invalid)  
callerid\_name.gsub!(/[^a-zA-Z0-9]/, " ");

```
      # Add a 1 if it's a US 9-digit number.
      callerid_name = ("1" + callerid_name) if callerid_name =~

```

/^[2-9]\d{9,9}$/

```
      # Be careful with changing headers. You could end up spending

```

a lot of  
# time debugging, checking why a call isn’t going through!  
(Been there!)  
Req.Header.from.FromURI.User = callerid\_name  
Req.Header.From.FromName = callerid\_name

```
      @NumbersToCall = TDialList.new
   end

   def Answer
      # Grab the rules
      tr = getTimeRule
      ur = getUnavailableRule

      # Insert unavailable rule, if needed
      unless ur.empty?
         tr.gsub!(/#{@@localuser}/, ur) if !Sys.IsAvailable
      end

      Sys.Log("Answer Rule used: #{tr}")

      # Start dialing each number in the rule, unless rule is set to

```

decline  
unless tr == “decline”  
tr.split(“#”).each { |number|  
Code,Reason = @NumbersToCall.append(TNumber.new(number))

```
            # If there was an error adding the number, don't let it

```

break  
# the answer rules, just remove it from the numbers to  
call.  
@NumbersToCall.deleteLast if Code \> 0  
}

```
         @NumbersToCall.dial
      end

      # If we end up here, that means the numbers dialed weren't

```

answered or  
# the rule is set to decline the call.  
Sys.Log(“Exhausted answer options (or decline rule).”)  
return 408, “#{@@localuser} is not available”  
end

```
   # Returns the time rule, based on the current sys time. Will

```

return  
# a default rule if no time rule exists.  
#  
def getTimeRule  
result = ‘’

```
      AnswerRules.each { |rule|
         # If the rule contains a from-to time format
         if

```

rule[0].match(/^(\d{1,2}):(\d{2,2})-(\d{1,2}):(\d{2,2})$/)  
# From what time do we start to check?  
t1 = Time.gm(@time.year, @time.month, @time.day,  
$1.to\_i, $2.to\_i)

```
            # And until what time? (We decrease the time by a

```

second)  
t2 = Time.gm(@time.year, @time.month, @time.day,  
$3.to\_i, $4.to\_i)  
t2 -= 1

```
            # If the start time is beyonthe end time, decrease start

```

time  
# by 24 hours  
t1 -= (3600 \* 24) if t1 \> t2

```
            result = rule[1] if @time.between?(t1,t2)
         else
            unless rule[0] =~ /^\$/
               result = rule[1] if Req.Header.From.FromName.to_s =~

```

/#{rule[0]}/  
end  
end  
}

```
      return result if !result.to_s.empty?

      # If we end up here, it means we couldn't find a matching time

```

rule.  
# So we look for a default rule. If none, we make a default  
rule.  
if AnswerRules[“$default”]  
return AnswerRules[“$default”]  
else  
return @@localuser  
end  
end

```
   # Returns the rule for handeling unavailable user. Will return
   # empty if no rule available.
   #
   def getUnavailableRule
      return AnswerRules["$unavailable"].to_s
   end
end

# A helper for figuring out if the number is:
# 1) a local call (MSS user -> MSS user)
# 2) an URI call (MSS user -> SIP Provider user)
# 3) a dialed phone call (MSS user -> PSTN)
#
def fixupNumber(aNumber)
   number = String.new(aNumber =~ /^(.+)@(.+)$/ ? $1.to_s : aNumber)
   host = $2.to_s.downcase
   port = host.sub!(/\:(\d+)/, "") ? $1 : ""

   if (host == "local")
      # It's a MSS user -> MSS user call
      number << "@" << LocalDomain

   elsif (host == "") or (Domains.find{|x| x.downcase == host})
      # It's a MSS user -> PSTN call, unless LocalAreaCode is

```

matched.  
# A LocalAreaCode is not valid if a 9 needs to be dialed for  
outgoing calls.

```
      if (!LocalAreaCode.empty?) and (!DialNineOut)
         # We have a LocalAreaCode, but we'll also check in case it

```

was  
# dialed with the country code (if specified)  
LACC = LocalAreaCode.gsub(/^0/, MyCountryCode)

```
         if number.sub!(/^#{LocalAreaCode}/,"") or

```

(number.sub!(/^#{LACC}/, “”) unless MyCountryCode.empty?)  
number \<\< “@” \<\< LocalDomain  
end  
elsif DialNineOut  
number \<\< “@” \<\< LocalDomain unless number.sub!(/^9/, “”)  
end

```
   else
      # It's a MSS -> URI call

      number << "@" << host
   end

   number << ":" << port unless port.empty?

   return number
end

# *********************************** MAIN

```

* * *

```
# This is where all the action happens, depending on incomming or

```

outgoing calls  
#

* * *

```
begin
   timeit = Time.now

   Sys.Log("** Call from #{Req.Header.From.ToString} to

```

#{Req.URI.ToString} \*\*")

```
   Code = 500
   Reason = 'Internal error'

   if Sys.In # Incoming call...
      InboundManager = TInboundMgr.new
      Code,Reason = InboundManager.Answer

   else # Outbound call ...
      dest = String.new(Req.URI.ToString.to_s)
      dest.sub!(/^sip:/, "") # strip "sip:"
      dest.gsub!(/%../) {|x| x[1,2].to_i(16).chr} # Convert %hh

```

into ASCII

```
      # Is it a Speeddial? (Nested speeddial no longer supported,

```

“adest” is  
# simply a temporart placeholder.  
adest = fixupNumber(dest)  
dest = Speeddial[adest] if (Speeddial[adest])

```
      # Create a new Dial List
      NumbersToCall = TDialList.new

      # Grab the phone number(s), seperated by a '#'
      dest.split("#").each { |number|
         # Add the number.
         Code,Reason = NumbersToCall.append(TNumber.new(number))

         # Did anything bad happen while adding this number?
         break if Code > 0
      }

      # Will stop script here if Code >= 200, ie error adding number
      Sys.Respond(Code, Reason) if Code > 0

      Code,Reason = NumbersToCall.dial
   end

   Sys.Respond(Code, Reason)

rescue
   # Gives a lot more details at what went wrong. Don't worry about

```

the Thread Exit.  
Sys.Log("\*\* Error: " + $!) unless $!.to\_s =~ /Thread was being  
aborted./

```
ensure
   Sys.Log("Time to complete Dial Plan: " + (Time.Now -

```

timeit).to\_s)  
end
