mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-06 12:36:58 +00:00
Update the conversion script from sip.conf to pjsip.conf
(closes issue ASTERISK-22374) Reported by Matt Jordan Review: https://reviewboard.asterisk.org/r/2846 ........ Merged revisions 402327 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@402328 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -3,11 +3,12 @@ import re
|
|||||||
from astdicts import OrderedDict
|
from astdicts import OrderedDict
|
||||||
from astdicts import MultiOrderedDict
|
from astdicts import MultiOrderedDict
|
||||||
|
|
||||||
|
|
||||||
def merge_values(left, right, key):
|
def merge_values(left, right, key):
|
||||||
"""Merges values from right into left."""
|
"""Merges values from right into left."""
|
||||||
if isinstance(left, list):
|
if isinstance(left, list):
|
||||||
vals0 = left
|
vals0 = left
|
||||||
else: # assume dictionary
|
else: # assume dictionary
|
||||||
vals0 = left[key] if key in left else []
|
vals0 = left[key] if key in left else []
|
||||||
vals1 = right[key] if key in right else []
|
vals1 = right[key] if key in right else []
|
||||||
|
|
||||||
@@ -15,14 +16,16 @@ def merge_values(left, right, key):
|
|||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
|
|
||||||
class Section(MultiOrderedDict):
|
class Section(MultiOrderedDict):
|
||||||
"""A Section is a MultiOrderedDict itself that maintains a list of
|
"""
|
||||||
key/value options. However, in the case of an Asterisk config
|
A Section is a MultiOrderedDict itself that maintains a list of
|
||||||
file a section may have other defaults sections that is can pull
|
key/value options. However, in the case of an Asterisk config
|
||||||
data from (i.e. templates). So when an option is looked up by key
|
file a section may have other defaults sections that is can pull
|
||||||
it first checks the base section and if not found looks in the
|
data from (i.e. templates). So when an option is looked up by key
|
||||||
added default sections. If not found at that point then a 'KeyError'
|
it first checks the base section and if not found looks in the
|
||||||
exception is raised.
|
added default sections. If not found at that point then a 'KeyError'
|
||||||
|
exception is raised.
|
||||||
"""
|
"""
|
||||||
count = 0
|
count = 0
|
||||||
|
|
||||||
@@ -35,9 +38,24 @@ class Section(MultiOrderedDict):
|
|||||||
self._templates = [] if templates is None else templates
|
self._templates = [] if templates is None else templates
|
||||||
|
|
||||||
def __cmp__(self, other):
|
def __cmp__(self, other):
|
||||||
|
"""
|
||||||
|
Use self.id as means of determining equality
|
||||||
|
"""
|
||||||
return cmp(self.id, other.id)
|
return cmp(self.id, other.id)
|
||||||
|
|
||||||
def get(self, key, from_self=True, from_templates=True, from_defaults=True):
|
def get(self, key, from_self=True, from_templates=True,
|
||||||
|
from_defaults=True):
|
||||||
|
"""
|
||||||
|
Get the values corresponding to a given key. The parameters to this
|
||||||
|
function form a hierarchy that determines priority of the search.
|
||||||
|
from_self takes priority over from_templates, and from_templates takes
|
||||||
|
priority over from_defaults.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
from_self - If True, search within the given section.
|
||||||
|
from_templates - If True, search in this section's templates.
|
||||||
|
from_defaults - If True, search within this section's defaults.
|
||||||
|
"""
|
||||||
if from_self and key in self:
|
if from_self and key in self:
|
||||||
return MultiOrderedDict.__getitem__(self, key)
|
return MultiOrderedDict.__getitem__(self, key)
|
||||||
|
|
||||||
@@ -62,13 +80,19 @@ class Section(MultiOrderedDict):
|
|||||||
raise KeyError(key)
|
raise KeyError(key)
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
"""Get the value for the given key. If it is not found in the 'self'
|
"""
|
||||||
then check inside templates and defaults before declaring raising
|
Get the value for the given key. If it is not found in the 'self'
|
||||||
a KeyError exception.
|
then check inside templates and defaults before declaring raising
|
||||||
|
a KeyError exception.
|
||||||
"""
|
"""
|
||||||
return self.get(key)
|
return self.get(key)
|
||||||
|
|
||||||
def keys(self, self_only=False):
|
def keys(self, self_only=False):
|
||||||
|
"""
|
||||||
|
Get the keys from this section. If self_only is True, then
|
||||||
|
keys from this section's defaults and templates are not
|
||||||
|
included in the returned value
|
||||||
|
"""
|
||||||
res = MultiOrderedDict.keys(self)
|
res = MultiOrderedDict.keys(self)
|
||||||
if self_only:
|
if self_only:
|
||||||
return res
|
return res
|
||||||
@@ -85,13 +109,21 @@ class Section(MultiOrderedDict):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
def add_defaults(self, defaults):
|
def add_defaults(self, defaults):
|
||||||
|
"""
|
||||||
|
Add a list of defaults to the section. Defaults are
|
||||||
|
sections such as 'general'
|
||||||
|
"""
|
||||||
defaults.sort()
|
defaults.sort()
|
||||||
for i in defaults:
|
for i in defaults:
|
||||||
self._defaults.insert(0, i)
|
self._defaults.insert(0, i)
|
||||||
|
|
||||||
def add_templates(self, templates):
|
def add_templates(self, templates):
|
||||||
templates.sort(reverse=True);
|
"""
|
||||||
self._templates.extend(templates)
|
Add a list of templates to the section.
|
||||||
|
"""
|
||||||
|
templates.sort()
|
||||||
|
for i in templates:
|
||||||
|
self._templates.insert(0, i)
|
||||||
|
|
||||||
def get_merged(self, key):
|
def get_merged(self, key):
|
||||||
"""Return a list of values for a given key merged from default(s)"""
|
"""Return a list of values for a given key merged from default(s)"""
|
||||||
@@ -120,9 +152,11 @@ COMMENT_END = '--;'
|
|||||||
|
|
||||||
DEFAULTSECT = 'general'
|
DEFAULTSECT = 'general'
|
||||||
|
|
||||||
|
|
||||||
def remove_comment(line, is_comment):
|
def remove_comment(line, is_comment):
|
||||||
"""Remove any commented elements from the line."""
|
"""Remove any commented elements from the line."""
|
||||||
if not line: return line, is_comment
|
if not line:
|
||||||
|
return line, is_comment
|
||||||
|
|
||||||
if is_comment:
|
if is_comment:
|
||||||
part = line.partition(COMMENT_END)
|
part = line.partition(COMMENT_END)
|
||||||
@@ -152,23 +186,21 @@ def remove_comment(line, is_comment):
|
|||||||
# check for eol comment
|
# check for eol comment
|
||||||
return line.partition(COMMENT)[0].strip(), False
|
return line.partition(COMMENT)[0].strip(), False
|
||||||
|
|
||||||
def try_include(line):
|
|
||||||
"""Checks to see if the given line is an include. If so return the
|
|
||||||
included filename, otherwise None.
|
|
||||||
"""
|
|
||||||
if not line.startswith('#'):
|
|
||||||
return None
|
|
||||||
|
|
||||||
# it is an include - get file name
|
def try_include(line):
|
||||||
try:
|
"""
|
||||||
return line[line.index('"') + 1:line.rindex('"')]
|
Checks to see if the given line is an include. If so return the
|
||||||
except ValueError:
|
included filename, otherwise None.
|
||||||
print "Invalid include - could not parse filename."
|
"""
|
||||||
return None
|
|
||||||
|
match = re.match('^#include\s*[<"]?(.*)[>"]?$', line)
|
||||||
|
return match.group(1) if match else None
|
||||||
|
|
||||||
|
|
||||||
def try_section(line):
|
def try_section(line):
|
||||||
"""Checks to see if the given line is a section. If so return the section
|
"""
|
||||||
name, otherwise return 'None'.
|
Checks to see if the given line is a section. If so return the section
|
||||||
|
name, otherwise return 'None'.
|
||||||
"""
|
"""
|
||||||
# leading spaces were stripped when checking for comments
|
# leading spaces were stripped when checking for comments
|
||||||
if not line.startswith('['):
|
if not line.startswith('['):
|
||||||
@@ -188,6 +220,7 @@ def try_section(line):
|
|||||||
except:
|
except:
|
||||||
return section[1:], False, templates
|
return section[1:], False, templates
|
||||||
|
|
||||||
|
|
||||||
def try_option(line):
|
def try_option(line):
|
||||||
"""Parses the line as an option, returning the key/value pair."""
|
"""Parses the line as an option, returning the key/value pair."""
|
||||||
data = re.split('=>?', line)
|
data = re.split('=>?', line)
|
||||||
@@ -196,30 +229,12 @@ def try_option(line):
|
|||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
def find_value(sections, key):
|
|
||||||
"""Given a list of sections, try to find value(s) for the given key."""
|
|
||||||
# always start looking in the last one added
|
|
||||||
sections.sort(reverse=True);
|
|
||||||
for s in sections:
|
|
||||||
try:
|
|
||||||
# try to find in section and section's templates
|
|
||||||
return s.get(key, from_defaults=False)
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# wasn't found in sections or a section's templates so check in defaults
|
|
||||||
for s in sections:
|
|
||||||
try:
|
|
||||||
# try to find in section's defaultsects
|
|
||||||
return s.get(key, from_self=False, from_templates=False)
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
raise KeyError(key)
|
|
||||||
|
|
||||||
def find_dict(mdicts, key, val):
|
def find_dict(mdicts, key, val):
|
||||||
"""Given a list of mult-dicts, return the multi-dict that contains
|
"""
|
||||||
the given key/value pair."""
|
Given a list of mult-dicts, return the multi-dict that contains
|
||||||
|
the given key/value pair.
|
||||||
|
"""
|
||||||
|
|
||||||
def found(d):
|
def found(d):
|
||||||
return key in d and val in d[key]
|
return key in d and val in d[key]
|
||||||
@@ -230,44 +245,25 @@ def find_dict(mdicts, key, val):
|
|||||||
raise LookupError("Dictionary not located for key = %s, value = %s"
|
raise LookupError("Dictionary not located for key = %s, value = %s"
|
||||||
% (key, val))
|
% (key, val))
|
||||||
|
|
||||||
def get_sections(parser, key, attr='_sections', searched=None):
|
|
||||||
if searched is None:
|
|
||||||
searched = []
|
|
||||||
if parser is None or parser in searched:
|
|
||||||
return []
|
|
||||||
|
|
||||||
try:
|
def write_dicts(config_file, mdicts):
|
||||||
sections = getattr(parser, attr)
|
"""Write the contents of the mdicts to the specified config file"""
|
||||||
res = sections[key] if key in sections else []
|
|
||||||
searched.append(parser)
|
|
||||||
return res + get_sections(parser._includes, key, attr, searched) \
|
|
||||||
+ get_sections(parser._parent, key, attr, searched)
|
|
||||||
except:
|
|
||||||
# assume ordereddict of parsers
|
|
||||||
res = []
|
|
||||||
for p in parser.itervalues():
|
|
||||||
res.extend(get_sections(p, key, attr, searched))
|
|
||||||
return res
|
|
||||||
|
|
||||||
def get_defaults(parser, key):
|
|
||||||
return get_sections(parser, key, '_defaults')
|
|
||||||
|
|
||||||
def write_dicts(file, mdicts):
|
|
||||||
for section, sect_list in mdicts.iteritems():
|
for section, sect_list in mdicts.iteritems():
|
||||||
# every section contains a list of dictionaries
|
# every section contains a list of dictionaries
|
||||||
for sect in sect_list:
|
for sect in sect_list:
|
||||||
file.write("[%s]\n" % section)
|
config_file.write("[%s]\n" % section)
|
||||||
for key, val_list in sect.iteritems():
|
for key, val_list in sect.iteritems():
|
||||||
# every value is also a list
|
# every value is also a list
|
||||||
for v in val_list:
|
for v in val_list:
|
||||||
key_val = key
|
key_val = key
|
||||||
if v is not None:
|
if v is not None:
|
||||||
key_val += " = " + str(v)
|
key_val += " = " + str(v)
|
||||||
file.write("%s\n" % (key_val))
|
config_file.write("%s\n" % (key_val))
|
||||||
file.write("\n")
|
config_file.write("\n")
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
|
|
||||||
class MultiOrderedConfigParser:
|
class MultiOrderedConfigParser:
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
self._parent = parent
|
self._parent = parent
|
||||||
@@ -275,16 +271,39 @@ class MultiOrderedConfigParser:
|
|||||||
self._sections = MultiOrderedDict()
|
self._sections = MultiOrderedDict()
|
||||||
self._includes = OrderedDict()
|
self._includes = OrderedDict()
|
||||||
|
|
||||||
|
def find_value(self, sections, key):
|
||||||
|
"""Given a list of sections, try to find value(s) for the given key."""
|
||||||
|
# always start looking in the last one added
|
||||||
|
sections.sort(reverse=True)
|
||||||
|
for s in sections:
|
||||||
|
try:
|
||||||
|
# try to find in section and section's templates
|
||||||
|
return s.get(key, from_defaults=False)
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# wasn't found in sections or a section's templates so check in
|
||||||
|
# defaults
|
||||||
|
for s in sections:
|
||||||
|
try:
|
||||||
|
# try to find in section's defaultsects
|
||||||
|
return s.get(key, from_self=False, from_templates=False)
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
raise KeyError(key)
|
||||||
|
|
||||||
def defaults(self):
|
def defaults(self):
|
||||||
return self._defaults
|
return self._defaults
|
||||||
|
|
||||||
def default(self, key):
|
def default(self, key):
|
||||||
"""Retrieves a list of dictionaries for a default section."""
|
"""Retrieves a list of dictionaries for a default section."""
|
||||||
return get_defaults(self, key)
|
return self.get_defaults(key)
|
||||||
|
|
||||||
def add_default(self, key, template_keys=None):
|
def add_default(self, key, template_keys=None):
|
||||||
"""Adds a default section to defaults, returning the
|
"""
|
||||||
default Section object.
|
Adds a default section to defaults, returning the
|
||||||
|
default Section object.
|
||||||
"""
|
"""
|
||||||
if template_keys is None:
|
if template_keys is None:
|
||||||
template_keys = []
|
template_keys = []
|
||||||
@@ -295,17 +314,47 @@ class MultiOrderedConfigParser:
|
|||||||
|
|
||||||
def section(self, key):
|
def section(self, key):
|
||||||
"""Retrieves a list of dictionaries for a section."""
|
"""Retrieves a list of dictionaries for a section."""
|
||||||
return get_sections(self, key)
|
return self.get_sections(key)
|
||||||
|
|
||||||
|
def get_sections(self, key, attr='_sections', searched=None):
|
||||||
|
"""
|
||||||
|
Retrieve a list of sections that have values for the given key.
|
||||||
|
The attr parameter can be used to control what part of the parser
|
||||||
|
to retrieve values from.
|
||||||
|
"""
|
||||||
|
if searched is None:
|
||||||
|
searched = []
|
||||||
|
if self in searched:
|
||||||
|
return []
|
||||||
|
|
||||||
|
sections = getattr(self, attr)
|
||||||
|
res = sections[key] if key in sections else []
|
||||||
|
searched.append(self)
|
||||||
|
if self._includes:
|
||||||
|
res += self._includes.get_sections(key, attr, searched)
|
||||||
|
if self._parent:
|
||||||
|
res += self._parent.get_sections(key, attr, searched)
|
||||||
|
return res
|
||||||
|
|
||||||
|
def get_defaults(self, key):
|
||||||
|
"""
|
||||||
|
Retrieve a list of defaults that have values for the given key.
|
||||||
|
"""
|
||||||
|
return self.get_sections(key, '_defaults')
|
||||||
|
|
||||||
def add_section(self, key, template_keys=None, mdicts=None):
|
def add_section(self, key, template_keys=None, mdicts=None):
|
||||||
|
"""
|
||||||
|
Create a new section in the configuration. The name of the
|
||||||
|
new section is the 'key' parameter.
|
||||||
|
"""
|
||||||
if template_keys is None:
|
if template_keys is None:
|
||||||
template_keys = []
|
template_keys = []
|
||||||
if mdicts is None:
|
if mdicts is None:
|
||||||
mdicts = self._sections
|
mdicts = self._sections
|
||||||
res = Section()
|
res = Section()
|
||||||
for t in template_keys:
|
for t in template_keys:
|
||||||
res.add_templates(get_defaults(self, t))
|
res.add_templates(self.get_defaults(t))
|
||||||
res.add_defaults(get_defaults(self, DEFAULTSECT))
|
res.add_defaults(self.get_defaults(DEFAULTSECT))
|
||||||
mdicts.insert(0, key, res)
|
mdicts.insert(0, key, res)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
@@ -313,29 +362,50 @@ class MultiOrderedConfigParser:
|
|||||||
return self._includes
|
return self._includes
|
||||||
|
|
||||||
def add_include(self, filename, parser=None):
|
def add_include(self, filename, parser=None):
|
||||||
|
"""
|
||||||
|
Add a new #include file to the configuration.
|
||||||
|
"""
|
||||||
if filename in self._includes:
|
if filename in self._includes:
|
||||||
return self._includes[filename]
|
return self._includes[filename]
|
||||||
|
|
||||||
self._includes[filename] = res = \
|
self._includes[filename] = res = \
|
||||||
MultiOrderedConfigParser(self) if parser is None else parser
|
MultiOrderedConfigParser(self) if parser is None else parser
|
||||||
return res;
|
return res
|
||||||
|
|
||||||
def get(self, section, key):
|
def get(self, section, key):
|
||||||
"""Retrieves the list of values from a section for a key."""
|
"""Retrieves the list of values from a section for a key."""
|
||||||
try:
|
try:
|
||||||
# search for the value in the list of sections
|
# search for the value in the list of sections
|
||||||
return find_value(self.section(section), key)
|
return self.find_value(self.section(section), key)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# section may be a default section so, search
|
# section may be a default section so, search
|
||||||
# for the value in the list of defaults
|
# for the value in the list of defaults
|
||||||
return find_value(self.default(section), key)
|
return self.find_value(self.default(section), key)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise LookupError("key %r not found for section %r"
|
raise LookupError("key %r not found for section %r"
|
||||||
% (key, section))
|
% (key, section))
|
||||||
|
|
||||||
|
def multi_get(self, section, key_list):
|
||||||
|
"""
|
||||||
|
Retrieves the list of values from a section for a list of keys.
|
||||||
|
This method is intended to be used for equivalent keys. Thus, as soon
|
||||||
|
as any match is found for any key in the key_list, the match is
|
||||||
|
returned. This does not concatenate the lookups of all of the keys
|
||||||
|
together.
|
||||||
|
"""
|
||||||
|
for i in key_list:
|
||||||
|
try:
|
||||||
|
return self.get(section, i)
|
||||||
|
except LookupError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Making it here means all lookups failed.
|
||||||
|
raise LookupError("keys %r not found for section %r" %
|
||||||
|
(key_list, section))
|
||||||
|
|
||||||
def set(self, section, key, val):
|
def set(self, section, key, val):
|
||||||
"""Sets an option in the given section."""
|
"""Sets an option in the given section."""
|
||||||
# TODO - set in multiple sections? (for now set in first)
|
# TODO - set in multiple sections? (for now set in first)
|
||||||
@@ -346,15 +416,17 @@ class MultiOrderedConfigParser:
|
|||||||
self.defaults(section)[0][key] = val
|
self.defaults(section)[0][key] = val
|
||||||
|
|
||||||
def read(self, filename):
|
def read(self, filename):
|
||||||
|
"""Parse configuration information from a file"""
|
||||||
try:
|
try:
|
||||||
with open(filename, 'rt') as file:
|
with open(filename, 'rt') as config_file:
|
||||||
self._read(file, filename)
|
self._read(config_file)
|
||||||
except IOError:
|
except IOError:
|
||||||
print "Could not open file ", filename, " for reading"
|
print "Could not open file ", filename, " for reading"
|
||||||
|
|
||||||
def _read(self, file, filename):
|
def _read(self, config_file):
|
||||||
is_comment = False # used for multi-lined comments
|
"""Parse configuration information from the config_file"""
|
||||||
for line in file:
|
is_comment = False # used for multi-lined comments
|
||||||
|
for line in config_file:
|
||||||
line, is_comment = remove_comment(line, is_comment)
|
line, is_comment = remove_comment(line, is_comment)
|
||||||
if not line:
|
if not line:
|
||||||
# line was empty or was a comment
|
# line was empty or was a comment
|
||||||
@@ -377,18 +449,19 @@ class MultiOrderedConfigParser:
|
|||||||
key, val = try_option(line)
|
key, val = try_option(line)
|
||||||
sect[key] = val
|
sect[key] = val
|
||||||
|
|
||||||
def write(self, f):
|
def write(self, config_file):
|
||||||
|
"""Write configuration information out to a file"""
|
||||||
try:
|
try:
|
||||||
for key, val in self._includes.iteritems():
|
for key, val in self._includes.iteritems():
|
||||||
val.write(key)
|
val.write(key)
|
||||||
f.write('#include "%s"\n' % key)
|
config_file.write('#include "%s"\n' % key)
|
||||||
|
|
||||||
f.write('\n')
|
config_file.write('\n')
|
||||||
write_dicts(f, self._defaults)
|
write_dicts(config_file, self._defaults)
|
||||||
write_dicts(f, self._sections)
|
write_dicts(config_file, self._sections)
|
||||||
except:
|
except:
|
||||||
try:
|
try:
|
||||||
with open(f, 'wt') as fp:
|
with open(config_file, 'wt') as fp:
|
||||||
self.write(fp)
|
self.write(fp)
|
||||||
except IOError:
|
except IOError:
|
||||||
print "Could not open file ", f, " for writing"
|
print "Could not open file ", config_file, " for writing"
|
1151
contrib/scripts/sip_to_pjsip/sip_to_pjsip.py
Executable file
1151
contrib/scripts/sip_to_pjsip/sip_to_pjsip.py
Executable file
File diff suppressed because it is too large
Load Diff
@@ -1,392 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# TODO:
|
|
||||||
# (1) There is more work to do here, at least for the sip.conf items that
|
|
||||||
# aren't currently parsed. An issue will be created for that.
|
|
||||||
# (2) All of the scripts should probably be passed through pylint and have
|
|
||||||
# as many PEP8 issues fixed as possible
|
|
||||||
# (3) A public review is probably warranted at that point of the entire script
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
import optparse
|
|
||||||
import astdicts
|
|
||||||
import astconfigparser
|
|
||||||
|
|
||||||
PREFIX = 'res_sip_'
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
### some utility functions
|
|
||||||
###############################################################################
|
|
||||||
def section_by_type(section, res_sip, type):
|
|
||||||
"""Finds a section based upon the given type, adding it if not found."""
|
|
||||||
try:
|
|
||||||
return astconfigparser.find_dict(
|
|
||||||
res_sip.section(section), 'type', type)
|
|
||||||
except LookupError:
|
|
||||||
# section for type doesn't exist, so add
|
|
||||||
sect = res_sip.add_section(section)
|
|
||||||
sect['type'] = type
|
|
||||||
return sect
|
|
||||||
|
|
||||||
def set_value(key=None, val=None, section=None, res_sip=None,
|
|
||||||
nmapped=None, type='endpoint'):
|
|
||||||
"""Sets the key to the value within the section in res_sip.conf"""
|
|
||||||
def _set_value(k, v, s, r, n):
|
|
||||||
set_value(key if key else k, v, s, r, n, type)
|
|
||||||
|
|
||||||
# if no value or section return the set_value
|
|
||||||
# function with the enclosed key and type
|
|
||||||
if not val and not section:
|
|
||||||
return _set_value
|
|
||||||
|
|
||||||
# otherwise try to set the value
|
|
||||||
section_by_type(section, res_sip, type)[key] = \
|
|
||||||
val[0] if isinstance(val, list) else val
|
|
||||||
|
|
||||||
def merge_value(key=None, val=None, section=None, res_sip=None,
|
|
||||||
nmapped=None, type='endpoint', section_to=None):
|
|
||||||
"""Merge values from the given section with those from the default."""
|
|
||||||
def _merge_value(k, v, s, r, n):
|
|
||||||
merge_value(key if key else k, v, s, r, n, type, section_to)
|
|
||||||
|
|
||||||
# if no value or section return the merge_value
|
|
||||||
# function with the enclosed key and type
|
|
||||||
if not val and not section:
|
|
||||||
return _merge_value
|
|
||||||
|
|
||||||
# should return a single value section list
|
|
||||||
sect = sip.section(section)[0]
|
|
||||||
# for each merged value add it to res_sip.conf
|
|
||||||
for i in sect.get_merged(key):
|
|
||||||
set_value(key, i, section_to if section_to else section,
|
|
||||||
res_sip, nmapped, type)
|
|
||||||
|
|
||||||
def is_in(s, sub):
|
|
||||||
"""Returns true if 'sub' is in 's'"""
|
|
||||||
return s.find(sub) != -1
|
|
||||||
|
|
||||||
def non_mapped(nmapped):
|
|
||||||
def _non_mapped(section, key, val):
|
|
||||||
"""Writes a non-mapped value from sip.conf to the non-mapped object."""
|
|
||||||
if section not in nmapped:
|
|
||||||
nmapped[section] = astconfigparser.Section()
|
|
||||||
if isinstance(val, list):
|
|
||||||
for v in val:
|
|
||||||
# since coming from sip.conf we can assume
|
|
||||||
# single section lists
|
|
||||||
nmapped[section][0][key] = v
|
|
||||||
else:
|
|
||||||
nmapped[section][0][key] = val
|
|
||||||
return _non_mapped
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
### mapping functions -
|
|
||||||
### define f(key, val, section) where key/val are the key/value pair to
|
|
||||||
### write to given section in res_sip.conf
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
def set_dtmfmode(key, val, section, res_sip, nmapped):
|
|
||||||
"""Sets the dtmfmode value. If value matches allowable option in res_sip
|
|
||||||
then map it, otherwise set it to none.
|
|
||||||
"""
|
|
||||||
# available res_sip.conf values: frc4733, inband, info, none
|
|
||||||
if val != 'inband' or val != 'info':
|
|
||||||
nmapped(section, key, val + " ; did not fully map - set to none")
|
|
||||||
val = 'none'
|
|
||||||
set_value(key, val, section, res_sip, nmapped)
|
|
||||||
|
|
||||||
def from_nat(key, val, section, res_sip, nmapped):
|
|
||||||
"""Sets values from nat into the appropriate res_sip.conf options."""
|
|
||||||
# nat from sip.conf can be comma separated list of values:
|
|
||||||
# yes/no, [auto_]force_rport, [auto_]comedia
|
|
||||||
if is_in(val, 'yes'):
|
|
||||||
set_value('rtp_symmetric', 'yes', section, res_sip, nmapped)
|
|
||||||
set_value('rewrite_contact', 'yes', section, res_sip, nmapped)
|
|
||||||
if is_in(val, 'comedia'):
|
|
||||||
set_value('rtp_symmetric', 'yes', section, res_sip, nmapped)
|
|
||||||
if is_in(val, 'force_rport'):
|
|
||||||
set_value('force_rport', 'yes', section, res_sip, nmapped)
|
|
||||||
set_value('rewrite_contact', 'yes', section, res_sip, nmapped)
|
|
||||||
|
|
||||||
def set_timers(key, val, section, res_sip, nmapped):
|
|
||||||
"""Sets the timers in res_sip.conf from the session-timers option
|
|
||||||
found in sip.conf.
|
|
||||||
"""
|
|
||||||
# res_sip.conf values can be yes/no, required, always
|
|
||||||
if val == 'originate':
|
|
||||||
set_value('timers', 'always', section, res_sip, nmapped)
|
|
||||||
elif val == 'accept':
|
|
||||||
set_value('timers', 'required', section, res_sip, nmapped)
|
|
||||||
elif val == 'never':
|
|
||||||
set_value('timers', 'no', section, res_sip, nmapped)
|
|
||||||
else:
|
|
||||||
set_value('timers', 'yes', section, res_sip, nmapped)
|
|
||||||
|
|
||||||
def set_direct_media(key, val, section, res_sip, nmapped):
|
|
||||||
"""Maps values from the sip.conf comma separated direct_media option
|
|
||||||
into res_sip.conf direct_media options.
|
|
||||||
"""
|
|
||||||
if is_in(val, 'yes'):
|
|
||||||
set_value('direct_media', 'yes', section, res_sip, nmapped)
|
|
||||||
if is_in(val, 'update'):
|
|
||||||
set_value('direct_media_method', 'update', section, res_sip, nmapped)
|
|
||||||
if is_in(val, 'outgoing'):
|
|
||||||
set_value('directed_media_glare_mitigation', 'outgoing', section, res_sip, nmapped)
|
|
||||||
if is_in(val, 'nonat'):
|
|
||||||
set_value('disable_directed_media_on_nat','yes', section, res_sip, nmapped)
|
|
||||||
if (val == 'no'):
|
|
||||||
set_value('direct_media', 'no', section, res_sip, nmapped)
|
|
||||||
|
|
||||||
def from_sendrpid(key, val, section, res_sip, nmapped):
|
|
||||||
"""Sets the send_rpid/pai values in res_sip.conf."""
|
|
||||||
if val == 'yes' or val == 'rpid':
|
|
||||||
set_value('send_rpid', 'yes', section, res_sip, nmapped)
|
|
||||||
elif val == 'pai':
|
|
||||||
set_value('send_pai', 'yes', section, res_sip, nmapped)
|
|
||||||
|
|
||||||
def set_media_encryption(key, val, section, res_sip, nmapped):
|
|
||||||
"""Sets the media_encryption value in res_sip.conf"""
|
|
||||||
if val == 'yes':
|
|
||||||
set_value('media_encryption', 'sdes', section, res_sip, nmapped)
|
|
||||||
|
|
||||||
def from_recordfeature(key, val, section, res_sip, nmapped):
|
|
||||||
"""If record on/off feature is set to automixmon then set
|
|
||||||
one_touch_recording, otherwise it can't be mapped.
|
|
||||||
"""
|
|
||||||
if val == 'automixmon':
|
|
||||||
set_value('one_touch_recording', 'yes', section, res_sip, nmapped)
|
|
||||||
else:
|
|
||||||
nmapped(section, key, val + " ; could not be fully mapped")
|
|
||||||
|
|
||||||
def from_progressinband(key, val, section, res_sip, nmapped):
|
|
||||||
"""Sets the inband_progress value in res_sip.conf"""
|
|
||||||
# progressinband can = yes/no/never
|
|
||||||
if val == 'never':
|
|
||||||
val = 'no'
|
|
||||||
set_value('inband_progress', val, section, res_sip, nmapped)
|
|
||||||
|
|
||||||
def from_host(key, val, section, res_sip, nmapped):
|
|
||||||
"""Sets contact info in an AOR section in in res_sip.conf using 'host'
|
|
||||||
data from sip.conf
|
|
||||||
"""
|
|
||||||
# all aors have the same name as the endpoint so makes
|
|
||||||
# it easy to endpoint's 'aors' value
|
|
||||||
set_value('aors', section, section, res_sip, nmapped)
|
|
||||||
if val != 'dynamic':
|
|
||||||
set_value('contact', val, section, res_sip, nmapped, 'aor')
|
|
||||||
else:
|
|
||||||
set_value('max_contacts', 1, section, res_sip, nmapped, 'aor')
|
|
||||||
|
|
||||||
def from_subscribemwi(key, val, section, res_sip, nmapped):
|
|
||||||
"""Checks the subscribemwi value in sip.conf. If yes places the
|
|
||||||
mailbox value in mailboxes within the endpoint, otherwise puts
|
|
||||||
it in the aor.
|
|
||||||
"""
|
|
||||||
mailboxes = sip.get('mailbox', section, res_sip)
|
|
||||||
type = 'endpoint' if val == 'yes' else 'aor'
|
|
||||||
set_value('mailboxes', mailboxes, section, res_sip, nmapped, type)
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
# options in res_sip.conf on an endpoint that have no sip.conf equivalent:
|
|
||||||
# type, rtp_ipv6, 100rel, trust_id_outbound, aggregate_mwi,
|
|
||||||
# connected_line_method
|
|
||||||
|
|
||||||
# known sip.conf peer keys that can be mapped to a res_sip.conf section/key
|
|
||||||
peer_map = [
|
|
||||||
# sip.conf option mapping function res_sip.conf option(s)
|
|
||||||
###########################################################################
|
|
||||||
['context', set_value],
|
|
||||||
['dtmfmode', set_dtmfmode],
|
|
||||||
['disallow', merge_value],
|
|
||||||
['allow', merge_value],
|
|
||||||
['nat', from_nat], # rtp_symmetric, force_rport,
|
|
||||||
# rewrite_contact
|
|
||||||
['icesupport', set_value('ice_support')],
|
|
||||||
['autoframing', set_value('use_ptime')],
|
|
||||||
['outboundproxy', set_value('outbound_proxy')],
|
|
||||||
['mohsuggest', set_value],
|
|
||||||
['session-timers', set_timers], # timers
|
|
||||||
['session-minse', set_value('timers_min_se')],
|
|
||||||
['session-expires', set_value('timers_sess_expires')],
|
|
||||||
['externip', set_value('external_media_address')],
|
|
||||||
['externhost', set_value('external_media_address')],
|
|
||||||
# identify_by ?
|
|
||||||
['directmedia', set_direct_media], # direct_media
|
|
||||||
# direct_media_method
|
|
||||||
# directed_media_glare_mitigation
|
|
||||||
# disable_directed_media_on_nat
|
|
||||||
['callerid', set_value], # callerid
|
|
||||||
['callingpres', set_value('callerid_privacy')],
|
|
||||||
['cid_tag', set_value('callerid_tag')],
|
|
||||||
['trustpid', set_value('trust_id_inbound')],
|
|
||||||
['sendrpid', from_sendrpid], # send_pai, send_rpid
|
|
||||||
['send_diversion', set_value],
|
|
||||||
['encrpytion', set_media_encryption],
|
|
||||||
['use_avpf', set_value],
|
|
||||||
['recordonfeature', from_recordfeature], # automixon
|
|
||||||
['recordofffeature', from_recordfeature], # automixon
|
|
||||||
['progressinband', from_progressinband], # in_band_progress
|
|
||||||
['callgroup', set_value],
|
|
||||||
['pickupgroup', set_value],
|
|
||||||
['namedcallgroup', set_value],
|
|
||||||
['namedpickupgroup', set_value],
|
|
||||||
['busylevel', set_value('devicestate_busy_at')],
|
|
||||||
|
|
||||||
############################ maps to an aor ###################################
|
|
||||||
|
|
||||||
['host', from_host], # contact, max_contacts
|
|
||||||
['subscribemwi', from_subscribemwi], # mailboxes
|
|
||||||
['qualifyfreq', set_value('qualify_frequency', type='aor')],
|
|
||||||
|
|
||||||
############################# maps to auth#####################################
|
|
||||||
# type = auth
|
|
||||||
# username
|
|
||||||
# password
|
|
||||||
# md5_cred
|
|
||||||
# realm
|
|
||||||
# nonce_lifetime
|
|
||||||
# auth_type
|
|
||||||
######################### maps to acl/security ################################
|
|
||||||
|
|
||||||
['permit', merge_value(type='security', section_to='acl')],
|
|
||||||
['deny', merge_value(type='security', section_to='acl')],
|
|
||||||
['acl', merge_value(type='security', section_to='acl')],
|
|
||||||
['contactpermit', merge_value(type='security', section_to='acl')],
|
|
||||||
['contactdeny', merge_value(type='security', section_to='acl')],
|
|
||||||
['contactacl', merge_value(type='security', section_to='acl')],
|
|
||||||
|
|
||||||
########################### maps to transport #################################
|
|
||||||
# type = transport
|
|
||||||
# protocol
|
|
||||||
# bind
|
|
||||||
# async_operations
|
|
||||||
# ca_list_file
|
|
||||||
# cert_file
|
|
||||||
# privkey_file
|
|
||||||
# password
|
|
||||||
# external_signaling_address - externip & externhost
|
|
||||||
# external_signaling_port
|
|
||||||
# external_media_address
|
|
||||||
# domain
|
|
||||||
# verify_server
|
|
||||||
# verify_client
|
|
||||||
# require_client_cert
|
|
||||||
# method
|
|
||||||
# cipher
|
|
||||||
# localnet
|
|
||||||
######################### maps to domain_alias ################################
|
|
||||||
# type = domain_alias
|
|
||||||
# domain
|
|
||||||
######################### maps to registration ################################
|
|
||||||
# type = registration
|
|
||||||
# server_uri
|
|
||||||
# client_uri
|
|
||||||
# contact_user
|
|
||||||
# transport
|
|
||||||
# outbound_proxy
|
|
||||||
# expiration
|
|
||||||
# retry_interval
|
|
||||||
# max_retries
|
|
||||||
# auth_rejection_permanent
|
|
||||||
# outbound_auth
|
|
||||||
########################### maps to identify ##################################
|
|
||||||
# type = identify
|
|
||||||
# endpoint
|
|
||||||
# match
|
|
||||||
]
|
|
||||||
|
|
||||||
def map_peer(sip, section, res_sip, nmapped):
|
|
||||||
for i in peer_map:
|
|
||||||
try:
|
|
||||||
# coming from sip.conf the values should mostly be a list with a
|
|
||||||
# single value. In the few cases that they are not a specialized
|
|
||||||
# function (see merge_value) is used to retrieve the values.
|
|
||||||
i[1](i[0], sip.get(section, i[0])[0], section, res_sip, nmapped)
|
|
||||||
except LookupError:
|
|
||||||
pass # key not found in sip.conf
|
|
||||||
|
|
||||||
def find_non_mapped(sections, nmapped):
|
|
||||||
for section, sect in sections.iteritems():
|
|
||||||
try:
|
|
||||||
# since we are pulling from sip.conf this should always
|
|
||||||
# be a single value list
|
|
||||||
sect = sect[0]
|
|
||||||
# loop through the section and store any values that were not mapped
|
|
||||||
for key in sect.keys(True):
|
|
||||||
for i in peer_map:
|
|
||||||
if i[0] == key:
|
|
||||||
break;
|
|
||||||
else:
|
|
||||||
nmapped(section, key, sect[key])
|
|
||||||
except LookupError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def convert(sip, filename, non_mappings):
|
|
||||||
res_sip = astconfigparser.MultiOrderedConfigParser()
|
|
||||||
non_mappings[filename] = astdicts.MultiOrderedDict()
|
|
||||||
nmapped = non_mapped(non_mappings[filename])
|
|
||||||
for section in sip.sections():
|
|
||||||
if section == 'authentication':
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
map_peer(sip, section, res_sip, nmapped)
|
|
||||||
|
|
||||||
find_non_mapped(sip.defaults(), nmapped)
|
|
||||||
find_non_mapped(sip.sections(), nmapped)
|
|
||||||
|
|
||||||
for key, val in sip.includes().iteritems():
|
|
||||||
res_sip.add_include(PREFIX + key, convert(val, PREFIX + key, non_mappings)[0])
|
|
||||||
return res_sip, non_mappings
|
|
||||||
|
|
||||||
def write_res_sip(filename, res_sip, non_mappings):
|
|
||||||
try:
|
|
||||||
with open(filename, 'wt') as fp:
|
|
||||||
fp.write(';--\n')
|
|
||||||
fp.write(';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n')
|
|
||||||
fp.write('Non mapped elements start\n')
|
|
||||||
fp.write(';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n')
|
|
||||||
astconfigparser.write_dicts(fp, non_mappings[filename])
|
|
||||||
fp.write(';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n')
|
|
||||||
fp.write('Non mapped elements end\n')
|
|
||||||
fp.write(';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n')
|
|
||||||
fp.write('--;\n\n')
|
|
||||||
# write out include file(s)
|
|
||||||
for key, val in res_sip.includes().iteritems():
|
|
||||||
write_res_sip(key, val, non_mappings)
|
|
||||||
fp.write('#include "%s"\n' % key)
|
|
||||||
fp.write('\n')
|
|
||||||
# write out mapped data elements
|
|
||||||
astconfigparser.write_dicts(fp, res_sip.defaults())
|
|
||||||
astconfigparser.write_dicts(fp, res_sip.sections())
|
|
||||||
|
|
||||||
except IOError:
|
|
||||||
print "Could not open file ", filename, " for writing"
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
def cli_options():
|
|
||||||
global PREFIX
|
|
||||||
usage = "usage: %prog [options] [input-file [output-file]]\n\n" \
|
|
||||||
"input-file defaults to 'sip.conf'\n" \
|
|
||||||
"output-file defaults to 'res_sip.conf'"
|
|
||||||
parser = optparse.OptionParser(usage=usage)
|
|
||||||
parser.add_option('-p', '--prefix', dest='prefix', default=PREFIX,
|
|
||||||
help='output prefix for include files')
|
|
||||||
|
|
||||||
options, args = parser.parse_args()
|
|
||||||
PREFIX = options.prefix
|
|
||||||
|
|
||||||
sip_filename = args[0] if len(args) else 'sip.conf'
|
|
||||||
res_sip_filename = args[1] if len(args) == 2 else 'res_sip.conf'
|
|
||||||
|
|
||||||
return sip_filename, res_sip_filename
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
sip_filename, res_sip_filename = cli_options()
|
|
||||||
# configuration parser for sip.conf
|
|
||||||
sip = astconfigparser.MultiOrderedConfigParser()
|
|
||||||
sip.read(sip_filename)
|
|
||||||
res_sip, non_mappings = convert(sip, res_sip_filename, dict())
|
|
||||||
write_res_sip(res_sip_filename, res_sip, non_mappings)
|
|
Reference in New Issue
Block a user