Phone-Controlled Google Voice Outbound Dial Plan

Catalog of dial plans
doohickey
Posts: 67
Joined: Fri Sep 04, 2009 5:14 am

Phone-Controlled Google Voice Outbound Dial Plan

Post by doohickey » Tue Dec 01, 2009 12:46 am

Phone-Controlled Google Voice Outbound Dial Plan
This is a Google Voice outbound dial plan created to provide a few useful features and a simplicity in configuration and usage. The main features are a completely phone-controlled speed dial function, forwarding phone selector, forwarding phone weighted randomizer, and pseudo 2-line phone. Other features included are a fallback phone, phone number formatter, and non-free call blocker. All the configuration settings are at the top of the dial plan.

Speed Dial
Speed dial numbers are stored and deleted, as well as dialed, using the phone. Upon each store/delete an updated speed dial list is emailed to the user. The speed dial list can also be emailed at any time by request of the user. Note: to use the email part of the speed dial feature, authorization must first be acquired from the SIPSorcery admin to use the SIPSorcery Email application. Information about the Email application can be found on this help page.
Speed dial numbers can have a maximum of 3 digits, providing an available number range of 0 to 999. There are approximately sixty speed dial slots available. The amount is dictated by the maximum size of a SIPSorcery database value, which is currently 1k.

Forwarding Phone Selector
Selection of the forwarding phone is done by phone. The user can set/change the default forwarding phone and, also, specify a particular forwarding phone to use on a per-call basis.
Forwarding phone keys are 1 digit in the range of 1 to 9, providing the availability of up to nine forwarding phones for Google Voice callback.

Forwarding Phone Weighted Randomizer
The weighted randomizer provides an alternative way to juggle forwarding phones rather than explicitly selecting them using the forwarding phone selector. Usage is very similar to the forwarding phone selector in that it, also, is set using the phone, it shares the same modifier key for phone entry, and the range of allowable numbers is 1 to 9. Where they differ is in the number of digits entered.
The weighted randomizer requires a minimum of two digits entered, anything less and that would be a selection. While the minimum is two digits, there is no defined maximum, and number repetition is not only allowed, it is an integral part of the feature. Number repetition is how "weight" is applied to the randomizer. The more times a specific number is entered into the randomizer, the greater the chance that the forwarding phone represented by that number will be used, and vice versa.

Pseudo 2-Line Phone
Calls can be dialed via either of two different Google Voice accounts. Line 1 is the default line and requires no special action to place calls on it. Line 2 calls are placed by appending an asterisk at the end of the number/string to be dialed.

Fallback Phone
When the fallback phone feature is enabled, a second callback attempt will be made in the event that the first does not connect. Fallback phone will always use a different forwarding phone, if available, than the one used for the initial callback attempt. If forwarding phones are being randomized with the weighted randomizer, another random phone will be used, else fallback phone uses the foremost unused forwarding phone.

Phone Number Formatter
11 digit numbers are left unchanged: ..................................................... 1(222)333-4444 --> 1(222)333-4444
10 digit numbers will be prefixed with a 1: ............................................... (222)333-4444 --> 1(222)333-4444
7 digit numbers will be prefixed with a 1 and the local area code: .................... 333-4444 --> 1(222)333-4444
Vanity numbers will have extraneous digits removed: .......................... 1(800)PIZZANOW --> 1(800)749-9266
International numbers will have the 011 replaced with a plus sign: ... 011 44 111222333 --> +44 111222333

Non-Free Call Blocker
All non-free numbers can be blocked, limiting allowable calls to Google Voice free calling destinations (currently USA and Canada) and disallowing calls to 900/976 numbers. The call blocker also includes a feature to pop holes in it, allowing non-free calls to only countries and territories explicitly specified by the user.


Dial Plan Usage
[Key: xxxxxxx = phone number | xxx = speed dial number | x = forwarding phone key(s)]

Dial a number, using the default (or randomized) forwarding phone¹:
xxxxxxx
Dial a number, using a specified forwarding phone¹:
xxxxxxx*x
Dial a speed dial number, using the default (or randomized) forwarding phone¹:
xxx
Dial a speed dial number, using a specified forwarding phone¹:
xxx*x

Set default forwarding phone or set weighted randomizer²:
*x

Store a speed dial number:
xxx#xxxxxxx

Delete a speed dial number:
xxx#000
Delete multiple speed dial numbers:
xxx*xxx*xxx#000
Delete a range of speed dial numbers:
xxx**xxx#000

Request speed dial list:
000


Notes:
¹ To call out on line 2 append an asterisk(*) at the end of the dialed number/string.
² An alternative entry method for the forwarding phone selector/randomizer is **x. This alternative is available for users who have a vertical service code conflict when entering a single asterisk followed by two digits.


Code: Select all

#####################################################################
#################  GOOGLE VOICE OUTBOUND DIAL PLAN  #################
#####################################################################
##    SIPSorcery Ruby dial plan for routing outbound calls via     ##
##    Google Voice featuring a completely phone-controlled         ##
##    speed dial function, forwarding phone selector, forwarding   ##
##    phone weighted randomizer, and 2-line Google Voice account   ##
##    selector. Other features are fallback phone, phone number    ##
##    formatter and call blocker.                                  ##
#####################################################################

# SIP tracing [true|false]
sys.Trace = false

# Google Voice account credentials
# GV syntax: GV[1..2] = ["username", "password", "number"]
GV = Hash.new   # Create object for accounts
GV[1] = ["username1", "password1", "2223334444"]
GV[2] = ["username2", "password2", "3334445555"]

# Google Voice forwarding phones
# PHONES syntax: PHONES[1..9] = ["phone", phoneType]
# phoneType key: [ 1:Home | 2:Mobile | 3:Work | 7:Gizmo ]
PHONES = Hash.new   # Create object for phones
PHONES[1] = ["17473334444", 7]      # Gizmo5
PHONES[2] = ["3603334444", 1]       # IPKall
PHONES[3] = ["4153334444", 1]       # Sipgate

# Time zone settings
# TIME_ZONE: standard time UTC offset
# DST_OBSERVED: locale observes daylight saving time [true|false]
TIME_ZONE = -5                      # EST (UTC-5)
DST_OBSERVED = true                 # DST is observed in New York

# Speed dial list email address
# Email sent upon speed dial number store, delete and by request.
# NOTE: this feature requires authorization from the SIPSorcery admin
# to use the SIPSorcery Email application.
EMAIL_ADDRESS = ""

# Allow calls only to free calling destinations [true|false]
# Free calling destinations are USA and Canada.
# Blocks calls to premium-rate 900/976 numbers.
FREE_CALLS_ONLY = true

# Enable fallback phone [true|false]
# Enable another callback attempt in the event that the first does not
# connect. Fallback phone will always use a different forwarding phone
# than used for the initial callback attempt, if available.
# If randomizing forwarding phones, another random phone will be used,
# else uses the foremost unused forwarding phone.
ENABLE_FALLBACK_PHONE = false

#####################################################################
### OPTIONAL SETTINGS

# Adjust the default callback timeout value that is in effect when
# fallback phone is enabled [default: 10]
# Timeout values can also be set per phone as a third parameter on
# each forwarding phone contained in the PHONES hash.
# All timeout adjustments apply only when fallback phone is enabled.
#CALLBACK_TIMEOUT = 10

# Manually set local area code and bypass the dial plan logic that
# determines local area code from the Google Voice number.
#AREA_CODE = ""

# Override FREE_CALLS_ONLY to allow international calls to countries
# specified by country code.
# Ex: INTL_COUNTRY_CODE_OVERRIDE = "44, 91" #allow calls to UK and India
#INTL_COUNTRY_CODE_OVERRIDE = ""

# Override FREE_CALLS_ONLY to allow non-free North American Numbering
# Plan calls to countries and territories specified by area code.
# Ex: NANP_AREA_CODE_OVERRIDE = "787, 939" #allow calls to Puerto Rico
#NANP_AREA_CODE_OVERRIDE = ""


#####################################################################
### DIAL PLAN LOGIC #################################################
#####################################################################

#####################################################################
### Regex patterns and data

PHONE_NUMBER_PATTERN = '(011\d+|(?:1?[2-9]\d{2})?[2-9]\d{6})\d*'
SPEED_DIAL_PATTERN = '\d|[1-9]\d{1,2}'
FWD_PHONE_PATTERN = '\*\*?([1-9]+)'
PREMIUM_RATE_PATTERNS = [
'1?900',                        # 900 numbers
'(?:1?[2-9]\d{2})?976\d{4}',    # 976 numbers
]
NANP_NON_FREE_AREA_CODES = [
'684',                      # American Samoa
'264',                      # Anguilla
'268',                      # Antigua & Barbuda
'242',                      # Bahamas
'246',                      # Barbados
'441',                      # Bermuda
'345',                      # Cayman Islands
'767',                      # Dominica
['809','829','849'],        # Dominican Republic
'473',                      # Grenada
'671',                      # Guam
'876',                      # Jamaica
'664',                      # Montserrat
'670',                      # Northern Mariana Islands
['787','939'],              # Puerto Rico
'869',                      # Saint Kitts and Nevis
'758',                      # Saint Lucia
'784',                      # Saint Vincent and the Grenadines
'721',                      # Sint Maarten
'868',                      # Trinidad and Tobago
'649',                      # Turks & Caicos
'284',                      # Virgin Islands (British)
'340',                      # Virgin Islands (US)
]

#####################################################################
### Define methods

# userTime(time_zone_int=0, dst_observed_bool=false) -> time
def userTime(tz=0, dst=false)
    @time = Time.new
    @offset = (dst && @time.dst? ? tz.to_i + 1 : tz.to_i) * 3600
    @time = @time.utc + @offset
end

# getHash(db_key_str) -> hash
# Read string from database, convert string into hash
def getHash(k)
    @h = sys.DBRead(k).to_s
    Hash[*@h.split(',')]
end

# putHash(db_key_str, hash, option_str=nil) -> nil
# Convert hash into string, write string to database
# Option: [ sort : sort hash by key ]
def putHash(k, h, option=nil)
    case option
    when 'sort'
        @v = h.sort {|a,b| a[0].to_i <=> b[0].to_i }.join(',')
    else
        @v = h.to_a.join(',')
    end
    sys.DBWrite(k,@v)
end

# filterPhoneNumber(phone_number_str) -> phone number string or abort call
def filterPhoneNumber(phone_number)
    if FREE_CALLS_ONLY
        # Apply international call overrides, if any
        if defined?(INTL_COUNTRY_CODE_OVERRIDE) && !INTL_COUNTRY_CODE_OVERRIDE.empty?
            @intl_a = "(?!#{INTL_COUNTRY_CODE_OVERRIDE.strip.gsub(/\D+/, '|')})"
        else
            @intl_a = ''
        end
        # Apply non-free NANP call overrides, if any
        if defined?(NANP_AREA_CODE_OVERRIDE) && !NANP_AREA_CODE_OVERRIDE.empty?
            @nanp_a = NANP_AREA_CODE_OVERRIDE.strip.gsub(/\D+/, '|')
            @nanp_na = NANP_NON_FREE_AREA_CODES.flatten.delete_if {|x| x =~ /#{@nanp_a}/ }.join('|')
        else
            @nanp_na = NANP_NON_FREE_AREA_CODES.flatten.join('|')
        end
        # Filter phone number through non-free call blocker
        case phone_number
        when /^(?:011#{@intl_a}|1?(?:#{@nanp_na})\d{7})/
            sys.Log("Toll calls to #{phone_number} are not allowed.\t")
            sys.Respond(403, "Call Not Allowed")
        when /^(?:#{PREMIUM_RATE_PATTERNS.join('|')})/
            sys.Log("Premium-rate calls to #{phone_number} are not allowed.\t")
            sys.Respond(403, "Call Not Allowed")
        end
    end
    # Format phone number
    if phone_number =~ /^011/
        # Apply international number formatting
        return phone_number.sub(/^011/, '+')
    else
        # Determine area code
        if defined?(AREA_CODE) && !AREA_CODE.empty?
            @area_code = AREA_CODE
        else
            @area_code = GV[GV_KEY][2][/^1?(\d{3})/, 1]
        end
        # Apply NANP number formatting, as needed
        return phone_number.rjust(11, "1#{@area_code}")
    end
end

# callGoogleVoice(phone_number_str, fwd_phone_array, timeout_int=30) -> nil
def callGoogleVoice(phone_number, phone, timeout=30)
    if ENABLE_FALLBACK_PHONE
        timeout = phone[2] || ( defined?(CALLBACK_TIMEOUT) ? CALLBACK_TIMEOUT : 10 )
    end
    sys.Log('-' * 50 + "\t")
    sys.Log("  Dialing via Google Voice: #{phone_number}\t")
    sys.Log("  Google Voice account: [#{GV_KEY}] #{GV[GV_KEY][2]}\t")
    sys.Log("  Forwarding phone: [#{PHONES.index(phone)}] #{phone[0]}\t")
    sys.Log('-' * 50 + "\t")
    sys.GoogleVoiceCall(GV[GV_KEY][0], GV[GV_KEY][1], phone[0], phone_number, GV[GV_KEY][2], phone[1], timeout)
end

# emailSpeedDial() -> nil
def emailSpeedDial
    unless defined?(EMAIL_ADDRESS) && !EMAIL_ADDRESS.empty? then return end
    @speed_dial = getHash('speed_dial')
    @title = "SIPSorcery Speed Dial List for #{sys.Username}"
    @time = userTime(TIME_ZONE, DST_OBSERVED).strftime("%b %d, %Y - %I:%M:%S %p")
    # Format speed dial list
    @speed_dial_list = Array.new
    @speed_dial.each_pair {|k,v|
        k = "[#{k}]".rjust(5, ' ')
        v = v.sub(/^1([2-9]\d{2})([2-9]\d{2})(\d{4})$/, '1(\1) \2-\3')
        @speed_dial_list.push("#{k}  #{v}")
    }
    # Format email body
    @body = String.new
    @body << "\n" * 2
    @body << @title.center(72)
    @body << "\n" * 2
    @body << @time.center(72)
    @body << "\n" * 4
    @list_length = @speed_dial_list.length
    @entry_lengths = @speed_dial_list.map {|v| v.length }
    @entry_lengths_max = @entry_lengths.max.to_i
    case @entry_lengths_max > 28 ? 1 : @list_length
    when 0
        @body << 'The speed dial list is empty.'.center(72)
    when 1..15
        @margin = [[
            (( 72 - ( @entry_lengths.inject(0.0) {|sum,v| sum + v } / @list_length )) / 2 ).floor,
            72 - @entry_lengths_max,
        ].min, 8].max
        until @speed_dial_list.empty?
            @body << ' ' * @margin
            @body << @speed_dial_list.shift.slice(0, 68 - @margin)
            @body << "\n"
        end
    when 16..1.0/0
        until @speed_dial_list.empty?
            @body << ' ' * 8
            @body << @speed_dial_list.shift.ljust(32, ' ')
            @body << @speed_dial_list.slice!(@list_length / 2).to_s
            @body << "\n"
        end
    end
    @body << "\n" * 5
    sys.Email(EMAIL_ADDRESS, "#{@title} (#{@time})", @body)
end

#####################################################################
### Prepare dialed number

dialed_number = req.URI.User.to_s

# Convert HEX(%hh) into ASCII
if dialed_number =~ /%/
    sys.Log("Dialed number converted: from: #{dialed_number}\t")
    dialed_number.gsub!(/%(..)/) {$1.hex.chr}
    sys.Log("Dialed number converted:   to: #{dialed_number}\t")
end

# Select Google Voice account
GV_KEY = dialed_number.slice!(/\*$/) ? 2 : 1

#####################################################################
### Process dialed number

case dialed_number
when /^(?:#{PHONE_NUMBER_PATTERN}|(#{SPEED_DIAL_PATTERN}))(?:#{FWD_PHONE_PATTERN})?$/
    # Dial phone number or speed dial number
    # Option: specify forwarding phone for this call
    if $2
        speed_dial = getHash('speed_dial')
        if phone_number = speed_dial[$2]
            sys.Log("Calling speed dial number: [#{$2}] #{phone_number}\t")
        else
            sys.Log("Speed dial number not found for key: [#{$2}]\t")
            sys.Respond(404, "Speed Dial Number Not Found")
        end
    else
        phone_number = filterPhoneNumber($1)
    end
    phones_key = ( $3 || sys.DBRead('fwd_phone') ).to_i
    unless phone = PHONES[phones_key]
        if phones_key.to_s.length > 1
            randomizer = phones_key.to_s.split(//).map {|s| s.to_i }
            randomizer.delete_if {|i| !PHONES.key? i }
            if randomizer.empty?
                sys.Log("Forwarding phone randomizer contains no valid keys: [#{phones_key}]\t")
                sys.Respond(400, "Invalid Forwarding Phone Randomizer Keys")
            else
                phones_key = randomizer.slice(rand(randomizer.length))
                phone = PHONES[phones_key]
                sys.Log("Forwarding phone randomized among the following keys: [#{randomizer}]\t")
            end
        elsif phones_key.zero?
            phone = PHONES.values.first
            sys.Log("Default forwarding phone not set, using first phone found.\t")
        else
            sys.Log("Forwarding phone not found for key: [#{phones_key}]\t")
            sys.Respond(404, "Forwarding Phone Not Found")
        end
    end
    callGoogleVoice(phone_number, phone)
    if ENABLE_FALLBACK_PHONE
        sys.Log("Call did not connect, trying fallback phone.\t")
        if randomizer && !randomizer.delete_if {|i| phones_key == i }.empty?
            phone = PHONES[randomizer.slice(rand(randomizer.length))]
            sys.Log("Fallback phone randomized among the following keys: [#{randomizer}]\t")
        else
            PHONES.length > 1 && PHONES.delete(phones_key)
            phone = PHONES.values.first
        end
        callGoogleVoice(phone_number, phone)
    end
when /^(#{SPEED_DIAL_PATTERN})##{PHONE_NUMBER_PATTERN}$/
    # Store speed dial number
    phone_number = filterPhoneNumber($2)
    speed_dial = getHash('speed_dial')
    speed_dial.store($1, phone_number)
    putHash('speed_dial', speed_dial, 'sort')
    sys.Log("Speed dial number stored: [#{$1}] #{phone_number}\t")
    emailSpeedDial
    sys.Respond(487, "Speed Dial Number Stored")
when /^((?:#{SPEED_DIAL_PATTERN})(?:(?:\*(?:#{SPEED_DIAL_PATTERN}))*|\*\*(?:#{SPEED_DIAL_PATTERN})))#000$/
    # Delete speed dial number(s)
    speed_dial = getHash('speed_dial')
    target = $1
    if target =~ /\*\*/
        range = true
        target = target.split('**').map {|s| s.to_i }
        if target[0] < target[1]
            speed_dial.delete_if {|k,v| (target[0]..target[1]).include? k.to_i }
        else
            sys.Log("Speed dial deletion invalid key range: [#{target.join('] to [')}]\t")
            sys.Respond(400, "Invalid Speed Dial Key Range")
        end
    else
        range = false
        target = target.split('*').uniq.map {|s| s.to_i }.sort
        speed_dial.delete_if {|k,v| target.include? k.to_i }
    end
    putHash('speed_dial', speed_dial)
    sys.Log("Speed dial number(s) deleted for key(s): [#{range ? target.join('] to [') : target.join('] [')}]\t")
    emailSpeedDial
    sys.Respond(487, "Speed Dial Number(s) Deleted")
when /^#{FWD_PHONE_PATTERN}$/
    # Set default or randomize forwarding phone
    if $1.length > 1
        # Set forwarding phone randomizer
        randomizer = $1
        orphan_keys = randomizer.split(//).uniq.select {|s| PHONES[s.to_i].nil? }
        if !orphan_keys.empty?
            sys.Log("Some randomizer keys have no matching forwarding phone: [#{orphan_keys.join('] [')}]\t")
            sys.Log("Keys will be stored as entered, randomizer may not perform as expected.\t")
        end
        sys.DBWrite('fwd_phone', randomizer)
        sys.Log("Forwarding phone randomizer set: [#{randomizer}]\t")
        sys.Respond(487, "Forwarding Phone Randomizer Set")
    else
        # Set forwarding phone
        phones_key = $1.to_i
        if PHONES[phones_key]
            sys.DBWrite('fwd_phone', phones_key.to_s)
            sys.Log("Forwarding phone set: [#{phones_key}] #{PHONES[phones_key][0]}\t")
            sys.Respond(487, "Forwarding Phone Set")
        else
            sys.Log("Forwarding phone not found for key: [#{phones_key}]\t")
            sys.Respond(404, "Forwarding Phone Not Found")
        end
    end
when /^000$/
    # Email speed dial list
    emailSpeedDial
    sys.Respond(487, "Speed Dial List Request Processed")
end

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

----------------------------------------------------------------------------------------------------
Update [2009_12_02]
Fix: the daylight saving time adjustment in the userTime method was corrected to jump ahead one hour, rather than fall back one hour.
----------------------------------------------------------------------------------------------------
Update [2009_12_07]
New: added Forwarding Phone Weighted Randomizer and Fallback Phone. These new features were inspired by Mike Telis' Alternating Google Voice Accounts dial plan.
----------------------------------------------------------------------------------------------------
Update [2009_12_12]
Fix: fallback phone was functioning only when using the forwarding phone weighted randomizer. It has been corrected to also function with the forwarding phone selector.
----------------------------------------------------------------------------------------------------
Update [2010_02_14]
New: added Pseudo 2-Line Phone.
----------------------------------------------------------------------------------------------------
Last edited by doohickey on Sun Feb 14, 2010 7:39 pm, edited 8 times in total.

jackhappy
Posts: 13
Joined: Sun Sep 13, 2009 8:52 pm

Post by jackhappy » Wed Dec 02, 2009 1:06 am

Thanks a TON!!!

doohickey
Posts: 67
Joined: Fri Sep 04, 2009 5:14 am

Post by doohickey » Wed Dec 02, 2009 6:40 pm

I'm glad you like it, jackhappy.

Please note the recent update. It's not a critical update as it has no bearing on the functionality of the dial plan. It's rather cosmetic, but what I would consider an important cosmetic. It affects the displayed time on speed dial list emails.

To avoid copying and pasting the whole dial plan over again, the following illustrates the complete change, which is, the minus sign has been changed to a plus sign on the @offset assignment line.

Code: Select all

# Old code
def userTime(tz=0, dst=false)
    @time = Time.new
    @offset = (dst && @time.dst? ? tz.to_i - 1 : tz.to_i) * 3600
    @time = @time.utc + @offset
end

# New code
def userTime(tz=0, dst=false)
    @time = Time.new
    @offset = (dst && @time.dst? ? tz.to_i + 1 : tz.to_i) * 3600
    @time = @time.utc + @offset
end

norske
Posts: 2
Joined: Sat Nov 28, 2009 12:15 am

Special privileges needed to receive an e-mail w/ the list?

Post by norske » Mon Dec 07, 2009 3:38 am

The dialplan is really slick, thanks.

It worked the very first try - but I got an error message that I didn't have the right admin privilege to receive an e-mail from sipsorcery.

Is there something else that I need to do?

doohickey
Posts: 67
Joined: Fri Sep 04, 2009 5:14 am

Post by doohickey » Mon Dec 07, 2009 4:53 am

You're welcome, norske.

One of my goals was to make the dial plan quick to get set up and running. Another goal, and an even more important one, was to make it simple enough to use for other household members that may not know, or care, what a dial plan is. If I told my girlfriend that I had a Ruby dial plan, she'd probably think I was getting ready to call the jewelry store to ask about a ring. Yet, she works this plan without a hitch.

About the speed dial email feature, it uses the SIPSorcery Email application. For security reasons, users need to get authorization from the SIPSorcery admin to use it. It's not a big deal, just need to send an email and ask. You can find the admin's email address and more info about the dial plan applications on this help page.
Last edited by doohickey on Fri Dec 11, 2009 11:23 pm, edited 1 time in total.

norske
Posts: 2
Joined: Sat Nov 28, 2009 12:15 am

LOL

Post by norske » Mon Dec 07, 2009 11:47 am

Doohickey - LOL about the potential for miscommunication with your girlfriend.

I finally found the admin's e-mail address after searching for the "@" character. The dark gray background on the sipsorcery help pages are really tough on my old eyes!

Having all of the necessary inputs in one concise area is a super way to go.

Thanks, again.

doohickey
Posts: 67
Joined: Fri Sep 04, 2009 5:14 am

Post by doohickey » Sat Dec 12, 2009 8:37 pm

A few days ago I added two new features to the dial plan (Forwarding Phone Weighted Randomizer and Fallback Phone) and was planning on elaborating on them down here in the comments, but shortly after updating the main post other responsibilities demanded my attention. Upon returning, the descriptions in the main post seemed sufficient, so I didn't post any further comment. Early this morning I applied a fix to one of these new features (Fallback Phone) and since I think it's important to bring attention to it for those who may be using this dial plan, I'll also take this opportunity to elaborate on the new features as well.

Forwarding Phone Weighted Randomizer is basically an expansion of the Forwarding Phone Selector. Rather than repeat any of the description from the main post, I'll use examples. Assume three forwarding phones: Gizmo is phone 1, IPKall is phone 2, and Sipgate is phone 3.

*1123 .................. use Gizmo 50% of the time, use IPKall and Sipgate 25% of the time each.
*22223 ................ use IPKall 80% of the time, Sipgate 20%, Gizmo never.
*1233333333 ...... use Sipgate 80% of the time, Gizmo 10%, IPKall 10%.
*123 .................... equally weight usage between the three phones.
*2 ........................ IPKall is selected as the default forwarding phone, randomizer not enabled.

The order of entry has no bearing on the weighted randomizer. The first four examples can also be entered as *2131, *22322, *3313333323, *321, and the results would be the same.

Fallback Phone, as previously described in the main post, initiates a second callback attempt in the event that the first does not connect. Which forwarding phone is used as the fallback phone differs depending on whether, or not, you are using the randomizer.
When using the randomizer, the fallback phone will use another, but different, phone that has been entered into the randomizer. If more than one unused phone is left in the randomizer, the fallback phone will be randomized among them.
When not using the randomizer, when you have selected a forwarding phone, the fallback phone will use the phone closest to the beginning of your phones list that hasn't already been used. If you have only one forwarding phone, it will use that phone again.

About the fix that was applied this morning, it was a correction to the Fallback Phone code. Fallback Phone was functioning only when the weighted randomizer was being used. This has been corrected and Fallback Phone now functions as it should with a selected forwarding phone, as well as with a randomized forwarding phone.

Well, that's all, folks. Wishing happy holidays and a joyous dial plan to all. ;)

doohickey
Posts: 67
Joined: Fri Sep 04, 2009 5:14 am

Post by doohickey » Sun Feb 14, 2010 8:00 pm

A new feature, Pseudo 2-Line Phone, has been added to the dial plan. As described in the main post, it allows dialing out on a second Google Voice account. While this feature is only useful for those who have two Google Voice accounts, two accounts are not required to use the dial plan.

To implement this feature, an assumption is made that each Google Voice account share the same forwarding phones. The phones in each account do not need to be an exact mirror of each other, but at the very minimum the phones used as the default selected/randomized forwarding phones should be shared among both accounts.

Besides the addition of this new feature, a minor change has been made to the dial plan usage. The dial pattern for speed dial deletion, which previously ended with a single zero, now ends with three zeros. The change was made because a single zero can be a valid speed dial key and, although there is currently no pattern conflict in the dial plan, future additions can be more easily accommodated by removing this potential conflict.

Enjoy

deputylynch
Posts: 2
Joined: Mon Feb 15, 2010 7:47 pm

Sip Sorcery Dial Plan Edit?

Post by deputylynch » Mon Feb 15, 2010 8:21 pm

How do I copy and paste any of this info to my SipSorcery Dialing Plan since all that happens when I try is a Silverlight Box pops up and won't allow any changes?

reraikes
Posts: 237
Joined: Thu Aug 13, 2009 10:15 pm

Post by reraikes » Mon Feb 15, 2010 9:42 pm

Control- x, c, and v work for me to cut, copy, and paste in the dial plan edit windows.

Post Reply