#
# Copyright (C) 2006 SIPfoundry Inc.
# Licensed by SIPfoundry under the LGPL license.
#
# Copyright (C) 2006 Pingtel Corp.
# Licensed to SIPfoundry under a Contributor Agreement.
#
##############################################################################
# system requires
require 'ipaddr'
# application requires
require 'exceptions'
require 'sipx_ipsocket'
require 'socket_utils'
class Utils
# Utils has only class methods, so don't allow instantiation.
private_class_method :new
public
# LATER: Add IPv6 matching
IPADDRV4 = '(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'
DOMAINLABEL = '[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?'
TOPLABEL = '[a-zA-Z]([a-zA-Z0-9]|-)*[a-zA-Z0-9]'
HOSTNAME = "(#{DOMAINLABEL}\\.)*#{TOPLABEL}"
HOST = "(#{IPADDRV4}|#{HOSTNAME})"
HOSTPORT = "#{HOST}(:\\d+)?"
SIPURI = ".*:(.+@)?(#{HOST})"
CONTACT = "(\\<?.*:(.+@)?#{HOSTPORT}).*\\>?"
EMBEDDEDQUOTES = '(\\\".*\\\")'
QUOTEDSTRING = "(\".*\")\s*(\\<.*:.*)"
# Take a contact string like "Jorma Kaukonen"<sip:187@10.1.1.170:1234>;tag=1c32681
# and extract just the host part, in this case "10.1.1.170". The "@" is optional,
# could be just "sip:10.1.1.170" for example.
def Utils.contact_host(contact)
# Use regular expression to extract the hostport part
if contact =~ Regexp.new(QUOTEDSTRING)
sip_uri = $2
else
sip_uri = contact
end
if sip_uri =~ Regexp.new(SIPURI)
$2
else
raise(BadContactException.new(contact),
"Bad contact, can't extract address: \"#{contact}\"")
end
end
# Look for the char in the str. If found, then remove that char and everything
# after it. Return the str.
def Utils.remove_part_of_str_beginning_with_char(str, char)
char_index = str.index(char)
if char_index
str = str[0...char_index]
end
str
end
# Return just the AOR part of a SIP From or To header, stripping the tag if
# one is present.
# If there is no tag then raise BadSipHeaderException if is_tag_required is true.
# :LATER: Use regex here, much simpler
def Utils.get_aor_from_header(header, is_tag_required = true)
aor = nil
# Strip quoted display name
if header =~ Regexp.new(QUOTEDSTRING)
sip_uri = $2
else
sip_uri = header
end
# Remember how long the display name was we chopped off and add that
# back on when getting the semicolon position
add_pos = header.length - sip_uri.length
# find the semicolon preceding the tag
semi = sip_uri.index(';')
# extract the AOR
if semi
# Add the length we originally stripped off
semi += add_pos
aor = header[0, semi]
else
if is_tag_required
raise(BadSipHeaderException. new(header),
'Tag missing from SIP header',
caller)
end
aor = header
end
# put '>' at the end to balance '<' at the start, if necessary
if aor[0] == ?< and aor[-1] != ?>
aor << '>'
end
aor
end
# Given a contact URL with params, like <sip:101@10.1.20.3:5100;play=https%3A%2F%2Flocalhost>,
# remove the params, which are preceded by semicolons. Usually there is a '>' at the end
# matching a '<' at the beginning. If so then leave it in place.
# :LATER: Use regex here, much simpler
def Utils.contact_without_params(contact)
if contact =~ Regexp.new(QUOTEDSTRING)
sip_uri = $2
else
sip_uri = contact
end
add_pos = contact.length - sip_uri.length
semi_index = sip_uri.index(';')
if semi_index
semi_index += add_pos
gt_index = contact.index('>')
contact = contact[0...semi_index]
contact << '>' if gt_index
end
contact
end
# Raise a CallResolverException. Include the stack trace.
def Utils.raise_exception(msg, klass = CallResolverException)
raise(klass, msg, caller)
end
# Given an events array, return a string that displays one event per line,
# with preceding newlines. Used for debugging.
def Utils.events_to_s(events)
events.inject('') {|str, event| str + "\n" + event.to_s}
end
end
syntax highlighted by Code2HTML, v. 0.9.1