[#365153] synchronize a "mocked" clock in a distributed system — Chuck Remes <cremes.devlist@...>

I've been banging on a problem for a few days now and don't feel any closer to solving it. I'm hoping some of the big brains on the ruby ML can shed some light. Following are a few paragraphs with a brief system overview before I state the problem. I apologize in advance for this question being only tangentially related to Ruby the language. :)

13 messages 2010/07/01
[#365164] Re: [Q] synchronize a "mocked" clock in a distributed system — Tony Arcieri <tony.arcieri@...> 2010/07/01

On Thu, Jul 1, 2010 at 3:10 PM, Chuck Remes <cremes.devlist@mac.com> wrote:

[#365214] RubyGoLightly Progress Report — Eleanor McHugh <eleanor@...>

I seem to have been missing in action for the best part of six months so =

14 messages 2010/07/02

[#365320] Why am I not getting the expected output? — Abder-rahman Ali <abder.rahman.ali@...>

I have the following code: http://pastie.org/1032525, but always getting

11 messages 2010/07/06

[#365351] best way to make .rb into an executable for linux? — David Ainley <wrinkliez@...>

I have a pretty basic .rb script that I would like to turn into an

11 messages 2010/07/06

[#365374] Hashes don't allow preceding commas by design? — Iain Barnett <iainspeed@...>

This is the output from irb that shows ruby 1.9.1 doesn't like hash =

12 messages 2010/07/07

[#365413] What is meant by those lines of code in this script? — Abder-rahman Ali <abder.rahman.ali@...>

I came across the following script from "Why's poignant guide to Ruby".

9 messages 2010/07/07

[#365504] FIRST PROGRAMMING PROBLEM Array — Francisco Martinez <calabazag@...>

Hi...I'm trying to solve a very simple exercise but this is one of my

12 messages 2010/07/09

[#365513] what about allowing to specify, which end belongs to which start? — Jan Lelis <prog@...>

Hi Ruby mailing list,

24 messages 2010/07/09
[#365541] Re: what about allowing to specify, which end belongs to which start? — Caleb Clausen <vikkous@...> 2010/07/10

On 7/9/10, Jan Lelis <prog@janlelis.de> wrote:

[#365548] Re: what about allowing to specify, which end belongs to which start? — Robert Klemme <shortcutter@...> 2010/07/11

On 10.07.2010 17:54, Caleb Clausen wrote:

[#365551] Re: what about allowing to specify, which end belongs to which start? — Caleb Clausen <vikkous@...> 2010/07/11

On 7/11/10, Robert Klemme <shortcutter@googlemail.com> wrote:

[#365555] Re: what about allowing to specify, which end belongs to which start? — Robert Klemme <shortcutter@...> 2010/07/11

On 11.07.2010 13:32, Caleb Clausen wrote:

[#365574] Re: what about allowing to specify, which end belongs to which start? — Caleb Clausen <vikkous@...> 2010/07/11

On 7/11/10, Robert Klemme <shortcutter@googlemail.com> wrote:

[#365570] How to pass a hash as a param to a method called through eval? — Alex Stahl <astahl@...5.com>

Hi Folks - I've got a data-driven app I'm building, and I'd like to be

14 messages 2010/07/11

[#365615] Try Ruby is back online. — andrew mcelroy <sophrinix@...>

Greetings,

10 messages 2010/07/12

[#365721] Ruby garabage collector — Abder-Rahman Ali <abder.rahman.ali@...>

In the "Why's poignant guide to Ruby" book, it states the following:

22 messages 2010/07/13

[#365752] What does this do? — Abder-Rahman Ali <abder.rahman.ali@...>

I have this portion of code from "Why's poignant guide to Ruby" book.

12 messages 2010/07/13

[#365828] click a javascript dialog window in Firefox — Mario Ruiz <tcblues@...>

Hi,

9 messages 2010/07/14

[#365844] Return nothing when looking outside the bounds of 2D array? — Shawn W_ <shawnw@...>

I have a 2D Array. I have written a method

22 messages 2010/07/14
[#365850] Re: Return nothing when looking outside the bounds of 2D array? — w_a_x_man <w_a_x_man@...> 2010/07/14

On Jul 14, 3:56=A0pm, Shawn W_ <sha...@internode.on.net> wrote:

[#365853] Re: Return nothing when looking outside the bounds of 2D array? — Shawn W_ <shawnw@...> 2010/07/15

Thx. Don't quite understand that code. I tried plugging in some nils but

[#365869] Re: Return nothing when looking outside the bounds of 2D array? — Shawn W_ <shawnw@...> 2010/07/15

A better way to describe it.

[#365871] Re: Return nothing when looking outside the bounds of 2D array? — Dave Howell <groups.2009a@...> 2010/07/15

I was going to suggest using the 'case' statement instead of all those =

[#365938] Re: Return nothing when looking outside the bounds of 2D array? — Shawn W_ <shawnw@...> 2010/07/16

Okay, just found out that...

[#365944] Re: Return nothing when looking outside the bounds of 2D array? — Martin DeMello <martindemello@...> 2010/07/16

On Fri, Jul 16, 2010 at 11:11 AM, Shawn W_ <shawnw@internode.on.net> wrote:

[#365847] Ruby best practice for "always on" app/service? — yermej <yermej@...>

I'm building an app that will essentially be a web service client. It

10 messages 2010/07/14

[#365988] client-side Ruby on iPad/iPhone? — Jeff Pritchard <jp@...>

I've seen jRuby and IronRuby, and really want to use them since i really

12 messages 2010/07/17

[#366015] ruby abstraction — "James O'Brien" <jeob32@...>

Hi,

17 messages 2010/07/18

[#366053] LoadError: no such file to load -- tk — Rich Leblanc <rl001@...>

I'm trying to install Ruby on a 64 bit Windows 7 machine following this

46 messages 2010/07/19
[#366063] Re: LoadError: no such file to load -- tk — Roger Pack <rogerpack2005@...> 2010/07/19

[#366082] Re: LoadError: no such file to load -- tk — Rich Leblanc <rl001@...> 2010/07/19

Roger Pack wrote:

[#366085] Re: LoadError: no such file to load -- tk — Eric Christopherson <echristopherson@...> 2010/07/19

On Mon, Jul 19, 2010 at 3:26 PM, Rich Leblanc <rl001@pacbell.net> wrote:

[#366086] Re: LoadError: no such file to load -- tk — Rich Leblanc <rl001@...> 2010/07/20

Eric Christopherson wrote:

[#366135] Re: LoadError: no such file to load -- tk — Roger Pack <rogerpack2005@...> 2010/07/20

[#366140] Re: LoadError: no such file to load -- tk — Rich Leblanc <rl001@...> 2010/07/20

Roger Pack wrote:

[#366147] Re: LoadError: no such file to load -- tk — Roger Pack <rogerpack2005@...> 2010/07/20

Rich Leblanc wrote:

[#366153] Re: LoadError: no such file to load -- tk — Rich Leblanc <rl001@...> 2010/07/20

Roger Pack wrote:

[#366179] Re: LoadError: no such file to load -- tk — Rich Leblanc <rl001@...> 2010/07/21

Rich Leblanc wrote:

[#366115] Count occurences of vars in array — Vitaliy Yanchuk <fuksito@...>

Hello, everyone.

18 messages 2010/07/20
[#366116] Re: Count occurences of vars in array — Jean-Julien Fleck <jeanjulien.fleck@...> 2010/07/20

Hello,

[#366120] Re: Count occurences of vars in array — Vitaliy Yanchuk <fuksito@...> 2010/07/20

Jean-Julien Fleck, thanks.

[#366152] Can't get ruby 1.9 to work after install on OSX — Musdev Musdev <devrubygem@...>

Hello

12 messages 2010/07/20

[#366196] how to make "gem install rmagick" work? — Jian Lin <blueskybreeze@...>

I wanted to install rmagick on Win7 but it can't install:

10 messages 2010/07/21

[#366226] Text to Binary — Umm Whyshouldisay <kipthemudkip@...>

Hi! I'm new to the forums. I'm also a bit new to Ruby. I already know

13 messages 2010/07/21

[#366254] finding last line in a file — Ted Flethuseo <flethuseo@...>

Hi everyone,

15 messages 2010/07/22
[#366256] Re: finding last line in a file — Urabe Shyouhei <shyouhei@...> 2010/07/22

Take a look at the doc for File.readline.

[#366257] Re: finding last line in a file — Urabe Shyouhei <shyouhei@...> 2010/07/22

(2010/07/22 14:08), Urabe Shyouhei wrote:

[#366319] Typical Ruby (non-rails) project structure. — Carl Jenkins <carljenkins@...>

What is/are the best-practice(s) for a Ruby project structure?

18 messages 2010/07/22

[#366418] Ruby books designed especially for beginngers — Kaye Ng <sbstn26@...>

Hey experts, i need your advice.

12 messages 2010/07/24

[#366611] Which Ruby is in use? — Hassan Schroeder <hassan.schroeder@...>

Is there a way to tell from within a program which executable is being

23 messages 2010/07/27
[#366614] Re: Which Ruby is in use? — "Joseph E. Savard" <joseph.savard@...> 2010/07/27

[#366617] Re: Which Ruby is in use? — Hassan Schroeder <hassan.schroeder@...> 2010/07/27

On Tue, Jul 27, 2010 at 2:20 PM, Joseph E. Savard

[#366620] Re: Which Ruby is in use? — Joel VanderWerf <joelvanderwerf@...> 2010/07/27

Hassan Schroeder wrote:

[#366622] Re: Which Ruby is in use? — Hassan Schroeder <hassan.schroeder@...> 2010/07/27

On Tue, Jul 27, 2010 at 3:10 PM, Joel VanderWerf

[#366624] Re: Which Ruby is in use? — Joel VanderWerf <joelvanderwerf@...> 2010/07/27

Hassan Schroeder wrote:

[#366625] Re: Which Ruby is in use? — Hassan Schroeder <hassan.schroeder@...> 2010/07/27

On Tue, Jul 27, 2010 at 3:52 PM, Joel VanderWerf

[#366626] Re: Which Ruby is in use? — Joel VanderWerf <joelvanderwerf@...> 2010/07/27

Hassan Schroeder wrote:

[#366629] tool to compare DB schema against DDL file — Fabian Marin <fmg134s@...>

First of all any feedback from you guys will be of tremendous help.

14 messages 2010/07/28

[#366727] my script just read one line? — Junhui Liao <junhui.liao@...>

Dear all,

19 messages 2010/07/29
[#366729] Re: my script just read one line? — Jes俍 Gabriel y Gal疣 <jgabrielygalan@...> 2010/07/29

On Thu, Jul 29, 2010 at 1:43 PM, Junhui Liao <junhui.liao@uclouvain.be> wro=

[#366766] Re: my script just read one line? — Junhui Liao <junhui.liao@...> 2010/07/29

Dear Jes炭s Gabriel y Gal叩n and all,

[#366774] Re: my script just read one line? — Jes俍 Gabriel y Gal疣 <jgabrielygalan@...> 2010/07/30

On Fri, Jul 30, 2010 at 1:58 AM, Junhui Liao <junhui.liao@uclouvain.be> wro=

[#366784] Re: my script just read one line? — Junhui Liao <junhui.liao@...> 2010/07/30

[#366786] Re: my script just read one line? — Jes俍 Gabriel y Gal疣 <jgabrielygalan@...> 2010/07/30

On Fri, Jul 30, 2010 at 2:18 PM, Junhui Liao <junhui.liao@uclouvain.be> wro=

[#366792] Re: my script just read one line? — Junhui Liao <junhui.liao@...> 2010/07/30

Dear Jes炭s Gabriel y Gal叩n,

[#366755] .any?{} Behavior — John Sikora <john.sikora@...>

I find the following behavior interesting (so interesting that I

28 messages 2010/07/29
[#366797] Re: [].all?{} and [].any?{} Behavior — Rick DeNatale <rick.denatale@...> 2010/07/30

On Thu, Jul 29, 2010 at 5:27 PM, John Sikora <john.sikora@xtera.com> wrote:

[#366809] Re: [].all?{} and [].any?{} Behavior — Josh Cheek <josh.cheek@...> 2010/07/30

On Fri, Jul 30, 2010 at 10:49 AM, Rick DeNatale <rick.denatale@gmail.com>wrote:

[#366837] Mocking a method with a block — Fernando Guillen <fguillen.mail@...>

Hi people,

12 messages 2010/07/31

Method error

From: Jochem Smit <ruby-forum.com@...>
Date: 2010-07-22 10:17:02 UTC
List: ruby-talk #366287
I use sipsorcery for my SIP-calls, which uses a ruby dialplan.

The dialplan i got from
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)
    #
    # 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"
    LocalDomain = "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
http://www.timeanddate.com/worldclock/difference.html
    #
    # 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:yourusername@mysipswitch.com>
    #
    # 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" => "303@sip.blueface.ie", "1" =>
"**500@voxalot.com" }
    Speeddial = {
       "9901" => "613@fwd.pulver.com",   # Echo test USA
       "9949" => "enum-echo-test@sip.nemox.net", # Echo test Germany
       "9944" => "sip:904@mouselike.org", # Call quality test UK
       "303" => "303@sip.blueface.ie",   # Calls speaking time @
blueface
       "612" => "612@fwd.pulver.com"   # 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" =>
"homephone@asip.com&mobilephone@asip.com"
    #
    # 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" =>
"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"
    }

    # 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:xxx@sipbroker.com>)
          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
-- 
Posted via http://www.ruby-forum.com/.

In This Thread

Prev Next