[asterisk-commits] dlee: branch dlee/ASTERISK-22296 r397678 - in /team/dlee/ASTERISK-22296: ./ b...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Aug 26 16:58:59 CDT 2013


Author: dlee
Date: Mon Aug 26 16:58:57 2013
New Revision: 397678

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=397678
Log:
Merged revisions 397565-397674 from http://svn.asterisk.org/svn/asterisk/trunk

Added:
    team/dlee/ASTERISK-22296/include/asterisk/bucket.h
      - copied unchanged from r397674, trunk/include/asterisk/bucket.h
    team/dlee/ASTERISK-22296/main/bucket.c
      - copied unchanged from r397674, trunk/main/bucket.c
    team/dlee/ASTERISK-22296/tests/test_bucket.c
      - copied unchanged from r397674, trunk/tests/test_bucket.c
Modified:
    team/dlee/ASTERISK-22296/   (props changed)
    team/dlee/ASTERISK-22296/bridges/bridge_builtin_interval_features.c
    team/dlee/ASTERISK-22296/bridges/bridge_native_rtp.c
    team/dlee/ASTERISK-22296/build_tools/menuselect-deps.in
    team/dlee/ASTERISK-22296/channels/Makefile
    team/dlee/ASTERISK-22296/channels/sig_pri.c
    team/dlee/ASTERISK-22296/configure
    team/dlee/ASTERISK-22296/configure.ac
    team/dlee/ASTERISK-22296/contrib/scripts/sip_to_res_sip/astconfigparser.py
    team/dlee/ASTERISK-22296/contrib/scripts/sip_to_res_sip/astdicts.py
    team/dlee/ASTERISK-22296/contrib/scripts/sip_to_res_sip/sip_to_res_sip.py
    team/dlee/ASTERISK-22296/include/asterisk/astmm.h
    team/dlee/ASTERISK-22296/include/asterisk/autoconfig.h.in
    team/dlee/ASTERISK-22296/include/asterisk/backtrace.h
    team/dlee/ASTERISK-22296/include/asterisk/bridge_channel.h
    team/dlee/ASTERISK-22296/include/asterisk/bridge_channel_internal.h
    team/dlee/ASTERISK-22296/include/asterisk/channel.h
    team/dlee/ASTERISK-22296/include/asterisk/config_options.h
    team/dlee/ASTERISK-22296/include/asterisk/lock.h
    team/dlee/ASTERISK-22296/include/asterisk/sorcery.h
    team/dlee/ASTERISK-22296/include/asterisk/stasis_app.h
    team/dlee/ASTERISK-22296/include/asterisk/stasis_app_impl.h
    team/dlee/ASTERISK-22296/include/asterisk/utils.h
    team/dlee/ASTERISK-22296/main/Makefile
    team/dlee/ASTERISK-22296/main/asterisk.c
    team/dlee/ASTERISK-22296/main/astmm.c
    team/dlee/ASTERISK-22296/main/astobj2.c
    team/dlee/ASTERISK-22296/main/backtrace.c
    team/dlee/ASTERISK-22296/main/bridge.c
    team/dlee/ASTERISK-22296/main/bridge_channel.c
    team/dlee/ASTERISK-22296/main/channel.c
    team/dlee/ASTERISK-22296/main/channel_internal_api.c
    team/dlee/ASTERISK-22296/main/config_options.c
    team/dlee/ASTERISK-22296/main/lock.c
    team/dlee/ASTERISK-22296/main/logger.c
    team/dlee/ASTERISK-22296/main/pbx.c
    team/dlee/ASTERISK-22296/main/sorcery.c
    team/dlee/ASTERISK-22296/main/stasis_channels.c
    team/dlee/ASTERISK-22296/main/utils.c
    team/dlee/ASTERISK-22296/makeopts.in
    team/dlee/ASTERISK-22296/res/ari/resource_bridges.c
    team/dlee/ASTERISK-22296/res/res_ari_bridges.c
    team/dlee/ASTERISK-22296/res/res_musiconhold.c
    team/dlee/ASTERISK-22296/res/res_pjsip.c
    team/dlee/ASTERISK-22296/res/res_pjsip/pjsip_configuration.c
    team/dlee/ASTERISK-22296/res/stasis/control.c
    team/dlee/ASTERISK-22296/rest-api/api-docs/bridges.json
    team/dlee/ASTERISK-22296/tests/test_config.c
    team/dlee/ASTERISK-22296/tests/test_sorcery.c
    team/dlee/ASTERISK-22296/tests/test_sorcery_astdb.c
    team/dlee/ASTERISK-22296/tests/test_sorcery_realtime.c

Propchange: team/dlee/ASTERISK-22296/
            ('branch-11-blocked' removed)

Propchange: team/dlee/ASTERISK-22296/
            ('branch-11-merged' removed)

Propchange: team/dlee/ASTERISK-22296/
------------------------------------------------------------------------------
    branch-12-merged = /branches/12:1-397673

Propchange: team/dlee/ASTERISK-22296/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Mon Aug 26 16:58:57 2013
@@ -1,1 +1,1 @@
-/trunk:1-397563
+/trunk:1-397677

Modified: team/dlee/ASTERISK-22296/bridges/bridge_builtin_interval_features.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ASTERISK-22296/bridges/bridge_builtin_interval_features.c?view=diff&rev=397678&r1=397677&r2=397678
==============================================================================
--- team/dlee/ASTERISK-22296/bridges/bridge_builtin_interval_features.c (original)
+++ team/dlee/ASTERISK-22296/bridges/bridge_builtin_interval_features.c Mon Aug 26 16:58:57 2013
@@ -103,12 +103,14 @@
 	/*
 	 * It may be necessary to resume music on hold after we finish
 	 * playing the announcment.
-	 *
-	 * XXX We have no idea what MOH class was in use before playing
-	 * the file.
 	 */
 	if (ast_test_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_MOH)) {
-		ast_moh_start(bridge_channel->chan, NULL, NULL);
+		const char *latest_musicclass;
+
+		ast_channel_lock(bridge_channel->chan);
+		latest_musicclass = ast_strdupa(ast_channel_latest_musicclass(bridge_channel->chan));
+		ast_channel_unlock(bridge_channel->chan);
+		ast_moh_start(bridge_channel->chan, latest_musicclass, NULL);
 	}
 }
 

Modified: team/dlee/ASTERISK-22296/bridges/bridge_native_rtp.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ASTERISK-22296/bridges/bridge_native_rtp.c?view=diff&rev=397678&r1=397677&r2=397678
==============================================================================
--- team/dlee/ASTERISK-22296/bridges/bridge_native_rtp.c (original)
+++ team/dlee/ASTERISK-22296/bridges/bridge_native_rtp.c Mon Aug 26 16:58:57 2013
@@ -112,8 +112,7 @@
 	return audio_glue0_res;
 }
 
-/*! \brief Start RTP native bridging */
-static int native_rtp_bridge_start(struct ast_bridge *bridge)
+static int native_rtp_bridge_start(struct ast_bridge *bridge, struct ast_channel *target)
 {
 	struct ast_bridge_channel *c0 = AST_LIST_FIRST(&bridge->channels);
 	struct ast_bridge_channel *c1 = AST_LIST_LAST(&bridge->channels);
@@ -152,10 +151,26 @@
 		break;
 
 	case AST_RTP_GLUE_RESULT_REMOTE:
-		glue0->update_peer(c0->chan, instance1, vinstance1, tinstance1, cap1, 0);
-		glue1->update_peer(c1->chan, instance0, vinstance0, tinstance0, cap0, 0);
-		ast_debug(2, "Remotely bridged '%s' and '%s' - media will flow directly between them\n",
-			ast_channel_name(c0->chan), ast_channel_name(c1->chan));
+
+		/* If we have a target, it's the channel that received the UNHOLD or UPDATE_RTP_PEER frame and was told to resume */
+		if (!target) {
+			glue0->update_peer(c0->chan, instance1, vinstance1, tinstance1, cap1, 0);
+			glue1->update_peer(c1->chan, instance0, vinstance0, tinstance0, cap0, 0);
+			ast_debug(2, "Remotely bridged '%s' and '%s' - media will flow directly between them\n",
+				ast_channel_name(c0->chan), ast_channel_name(c1->chan));
+		} else {
+			/*
+			 * If a target was provided, it is the recipient of an unhold or an update and needs to have
+			 * its media redirected to fit the current remote bridging needs. The other channel is either
+			 * already set up to handle the new media path or will have its own set of updates independent
+			 * of this pass.
+			 */
+			if (c0->chan == target) {
+				glue0->update_peer(c0->chan, instance1, vinstance1, tinstance1, cap1, 0);
+			} else {
+				glue1->update_peer(c1->chan, instance0, vinstance0, tinstance0, cap0, 0);
+			}
+		}
 		break;
 	case AST_RTP_GLUE_RESULT_FORBID:
 		break;
@@ -164,8 +179,7 @@
 	return 0;
 }
 
-/*! \brief Stop RTP native bridging */
-static void native_rtp_bridge_stop(struct ast_bridge *bridge)
+static void native_rtp_bridge_stop(struct ast_bridge *bridge, struct ast_channel *target)
 {
 	struct ast_bridge_channel *c0 = AST_LIST_FIRST(&bridge->channels);
 	struct ast_bridge_channel *c1 = AST_LIST_LAST(&bridge->channels);
@@ -193,9 +207,21 @@
 		}
 		break;
 	case AST_RTP_GLUE_RESULT_REMOTE:
-		glue0->update_peer(c0->chan, NULL, NULL, NULL, NULL, 0);
-		if (glue1) {
-			glue1->update_peer(c1->chan, NULL, NULL, NULL, NULL, 0);
+		if (!target) {
+			glue0->update_peer(c0->chan, NULL, NULL, NULL, NULL, 0);
+			if (glue1) {
+				glue1->update_peer(c1->chan, NULL, NULL, NULL, NULL, 0);
+			}
+		} else {
+			/*
+			 * If a target was provided, it is being put on hold and should expect to
+			 * receive mediafrom sterisk instead of what it was previously connected to.
+			 */
+			if (c0->chan == target) {
+				glue0->update_peer(c0->chan, NULL, NULL, NULL, NULL, 0);
+			} else if (glue1) {
+				glue1->update_peer(c1->chan, NULL, NULL, NULL, NULL, 0);
+			}
 		}
 		break;
 	case AST_RTP_GLUE_RESULT_FORBID:
@@ -221,9 +247,9 @@
 
 	if (bridge) {
 		if (f->subclass.integer == AST_CONTROL_HOLD) {
-			native_rtp_bridge_stop(bridge);
+			native_rtp_bridge_stop(bridge, chan);
 		} else if ((f->subclass.integer == AST_CONTROL_UNHOLD) || (f->subclass.integer == AST_CONTROL_UPDATE_RTP_PEER)) {
-			native_rtp_bridge_start(bridge);
+			native_rtp_bridge_start(bridge, chan);
 		}
 	}
 
@@ -375,7 +401,7 @@
 		return -1;
 	}
 
-	return native_rtp_bridge_start(bridge);
+	return native_rtp_bridge_start(bridge, NULL);
 }
 
 static void native_rtp_bridge_unsuspend(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel)
@@ -387,7 +413,7 @@
 {
 	native_rtp_bridge_framehook_detach(bridge_channel);
 
-	native_rtp_bridge_stop(bridge);
+	native_rtp_bridge_stop(bridge, NULL);
 }
 
 static int native_rtp_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)

Modified: team/dlee/ASTERISK-22296/build_tools/menuselect-deps.in
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ASTERISK-22296/build_tools/menuselect-deps.in?view=diff&rev=397678&r1=397677&r2=397678
==============================================================================
--- team/dlee/ASTERISK-22296/build_tools/menuselect-deps.in (original)
+++ team/dlee/ASTERISK-22296/build_tools/menuselect-deps.in Mon Aug 26 16:58:57 2013
@@ -26,6 +26,7 @@
 IXJUSER=@PBX_IXJUSER@
 JACK=@PBX_JACK@
 JANSSON=@PBX_JANSSON@
+URIPARSER=@PBX_URIPARSER@
 KQUEUE=@PBX_KQUEUE@
 LDAP=@PBX_LDAP@
 LIBEDIT=@PBX_LIBEDIT@

Modified: team/dlee/ASTERISK-22296/channels/Makefile
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ASTERISK-22296/channels/Makefile?view=diff&rev=397678&r1=397677&r2=397678
==============================================================================
--- team/dlee/ASTERISK-22296/channels/Makefile (original)
+++ team/dlee/ASTERISK-22296/channels/Makefile Mon Aug 26 16:58:57 2013
@@ -63,6 +63,7 @@
 
 clean::
 	$(MAKE) -C misdn clean
+	rm -f dahdi/*.o dahdi/*.i
 	rm -f sip/*.o sip/*.i
 	rm -f iax2/*.o iax2/*.i
 	rm -f h323/libchanh323.a h323/Makefile.ast h323/*.o h323/*.dep

Modified: team/dlee/ASTERISK-22296/channels/sig_pri.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ASTERISK-22296/channels/sig_pri.c?view=diff&rev=397678&r1=397677&r2=397678
==============================================================================
--- team/dlee/ASTERISK-22296/channels/sig_pri.c (original)
+++ team/dlee/ASTERISK-22296/channels/sig_pri.c Mon Aug 26 16:58:57 2013
@@ -9430,7 +9430,7 @@
 			info_str = pri_dump_info_str(pri->pri);
 			if (info_str) {
 				ast_cli(fd, "%s", info_str);
-				free(info_str);
+				ast_std_free(info_str);
 			}
 #else
 			pri_dump_info(pri->pri);

Modified: team/dlee/ASTERISK-22296/configure.ac
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ASTERISK-22296/configure.ac?view=diff&rev=397678&r1=397677&r2=397678
==============================================================================
--- team/dlee/ASTERISK-22296/configure.ac (original)
+++ team/dlee/ASTERISK-22296/configure.ac Mon Aug 26 16:58:57 2013
@@ -408,6 +408,7 @@
 AST_EXT_LIB_SETUP([ISDNNET], [ISDN4Linux], [isdnnet])
 AST_EXT_LIB_SETUP([JACK], [Jack Audio Connection Kit], [jack])
 AST_EXT_LIB_SETUP([JANSSON], [Jansson JSON library], [jansson])
+AST_EXT_LIB_SETUP([URIPARSER], [uriparser library], [uriparser])
 AST_EXT_LIB_SETUP([KQUEUE], [kqueue support], [kqueue])
 AST_EXT_LIB_SETUP([LDAP], [OpenLDAP], [ldap])
 AST_LIBCURL_CHECK_CONFIG([], [7.10.1])
@@ -543,6 +544,8 @@
 if test "x$JANSSON_LIB" == "x"; then
   AC_MSG_ERROR([*** JSON support not found (this typically means the libjansson development package is missing)])
 fi
+
+AST_EXT_LIB_CHECK([URIPARSER], [uriparser], [uriParseUriA], [uriparser/Uri.h])
 
 # Another mandatory item (unless it's explicitly disabled)
 AC_ARG_ENABLE([xmldoc],

Modified: team/dlee/ASTERISK-22296/contrib/scripts/sip_to_res_sip/astconfigparser.py
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ASTERISK-22296/contrib/scripts/sip_to_res_sip/astconfigparser.py?view=diff&rev=397678&r1=397677&r2=397678
==============================================================================
--- team/dlee/ASTERISK-22296/contrib/scripts/sip_to_res_sip/astconfigparser.py (original)
+++ team/dlee/ASTERISK-22296/contrib/scripts/sip_to_res_sip/astconfigparser.py Mon Aug 26 16:58:57 2013
@@ -1,3 +1,6 @@
+import re
+
+from astdicts import OrderedDict
 from astdicts import MultiOrderedDict
 
 def merge_values(left, right, key):
@@ -21,93 +24,197 @@
        added default sections. If not found at that point then a 'KeyError'
        exception is raised.
     """
-    def __init__(self, defaults = []):
+    count = 0
+
+    def __init__(self, defaults=None, templates=None):
         MultiOrderedDict.__init__(self)
-        self._defaults = defaults
+        # track an ordered id of sections
+        Section.count += 1
+        self.id = Section.count
+        self._defaults = [] if defaults is None else defaults
+        self._templates = [] if templates is None else templates
+
+    def __cmp__(self, other):
+        return cmp(self.id, other.id)
+
+    def get(self, key, from_self=True, from_templates=True, from_defaults=True):
+        if from_self and key in self:
+            return MultiOrderedDict.__getitem__(self, key)
+
+        if from_templates:
+            if self in self._templates:
+                return []
+            for t in self._templates:
+                try:
+                    # fail if not found on the search - doing it this way
+                    # allows template's templates to be searched.
+                    return t.get(key, True, from_templates, from_defaults)
+                except KeyError:
+                    pass
+
+        if from_defaults:
+            for d in self._defaults:
+                try:
+                    return d.get(key, True, from_templates, from_defaults)
+                except KeyError:
+                    pass
+
+        raise KeyError(key)
 
     def __getitem__(self, key):
         """Get the value for the given key. If it is not found in the 'self'
-           then check inside the defaults before declaring unable to locate."""
-        if key in self:
-            return MultiOrderedDict.__getitem__(self, key)
-
-        for default in self._defaults:
-            if key in default:
-                return default[key]
-
-        raise KeyError(key)
-
-    def keys(self):
+           then check inside templates and defaults before declaring raising
+           a KeyError exception.
+        """
+        return self.get(key)
+
+    def keys(self, self_only=False):
         res = MultiOrderedDict.keys(self)
+        if self_only:
+            return res
+
+        for d in self._templates:
+            for key in d.keys():
+                if key not in res:
+                    res.append(key)
+
         for d in self._defaults:
             for key in d.keys():
                 if key not in res:
                     res.append(key)
         return res
 
-    def add_default(self, default):
-        self._defaults.append(default)
+    def add_defaults(self, defaults):
+        defaults.sort()
+        for i in defaults:
+            self._defaults.insert(0, i)
+
+    def add_templates(self, templates):
+        templates.sort(reverse=True);
+        self._templates.extend(templates)
 
     def get_merged(self, key):
         """Return a list of values for a given key merged from default(s)"""
         # first merge key/values from defaults together
         merged = []
-        for i in self._defaults:
+        for i in reversed(self._defaults):
             if not merged:
                 merged = i
                 continue
             merged = merge_values(merged, i, key)
+
+        for i in reversed(self._templates):
+            if not merged:
+                merged = i
+                continue
+            merged = merge_values(merged, i, key)
+
         # then merge self in
         return merge_values(merged, self, key)
 
 ###############################################################################
 
-def remove_comment(line):
-    """Remove any commented elements from the given line"""
-    line = line.partition(COMMENT)[0]
-    return line.rstrip()
+COMMENT = ';'
+COMMENT_START = ';--'
+COMMENT_END = '--;'
+
+DEFAULTSECT = 'general'
+
+def remove_comment(line, is_comment):
+    """Remove any commented elements from the line."""
+    if not line: return line, is_comment
+
+    if is_comment:
+        part = line.partition(COMMENT_END)
+        if part[1]:
+            # found multi-line comment end check string after it
+            return remove_comment(part[2], False)
+        return "", True
+
+    part = line.partition(COMMENT_START)
+    if part[1]:
+        # found multi-line comment start check string before
+        # it to make sure there wasn't an eol comment in it
+        has_comment = part[0].partition(COMMENT)
+        if has_comment[1]:
+            # eol comment found return anything before it
+            return has_comment[0], False
+
+        # check string after it to see if the comment ends
+        line, is_comment = remove_comment(part[2], True)
+        if is_comment:
+            # return possible string data before comment
+            return part[0].strip(), True
+
+        # otherwise it was an embedded comment so combine
+        return ''.join([part[0].strip(), ' ', line]).rstrip(), False
+
+    # check for eol comment
+    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
+    try:
+        return line[line.index('"') + 1:line.rindex('"')]
+    except ValueError:
+        print "Invalid include - could not parse filename."
+        return None
 
 def try_section(line):
     """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
     if not line.startswith('['):
-        return None
-
-    first, second, third = line.partition(']')
-    # TODO - third may contain template, parse to see if it is a template
-    #        or is a list of templates...return?
-    return first[1:]
+        return None, False, []
+
+    section, delim, templates = line.partition(']')
+    if not templates:
+        return section[1:], False, []
+
+    # strip out the parens and parse into an array
+    templates = templates.replace('(', "").replace(')', "").split(',')
+    # go ahead and remove extra whitespace
+    templates = [i.strip() for i in templates]
+    try:
+        templates.remove('!')
+        return section[1:], True, templates
+    except:
+        return section[1:], False, templates
 
 def try_option(line):
     """Parses the line as an option, returning the key/value pair."""
-    first, second, third = line.partition('=')
-    return first.strip(), third.strip()
+    data = re.split('=>?', line)
+    # should split in two (key/val), but either way use first two elements
+    return data[0].rstrip(), data[1].lstrip()
 
 ###############################################################################
 
-def get_value(mdict, key, index=-1):
-    """Given a multi-dict, retrieves a value for the given key. If the key only
-       holds a single value return that value. If the key holds more than one
-       value and an index is given that is greater than or equal to zero then
-       return the value at the index. Otherwise return the list of values."""
-    vals = mdict[key]
-    if len(vals) == 1:
-        return vals[0]
-    if index >= 0:
-        return vals[index]
-    return vals
-
-def find_value(mdicts, key, index=-1):
-    """Given a list of multi-dicts, try to find value(s) for the given key."""
-    if not isinstance(mdicts, list):
-        # given a single multi-dict
-        return get_value(mdicts, key, index)
-
-    for d in mdicts:
-        if key in d:
-            return d[key]
-    # not found, throw error
+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):
@@ -115,80 +222,128 @@
        the given key/value pair."""
 
     def found(d):
-        # just check the first value of the key
-        return key in d and d[key][0] == val
-
-    if isinstance(mdicts, list):
-        try:
-            return [d for d in mdicts if found(d)][0]
-        except IndexError:
-            pass
-    elif found(mdicts):
-        return mdicts
-
-    raise LookupError("Dictionary not located for key = %s, value = %s"
-                      % (key, val))
+        return key in d and val in d[key]
+
+    try:
+        return [d for d in mdicts if found(d)][0]
+    except IndexError:
+        raise LookupError("Dictionary not located for key = %s, value = %s"
+                          % (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:
+        sections = getattr(parser, attr)
+        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():
+        # every section contains a list of dictionaries
+        for sect in sect_list:
+            file.write("[%s]\n" % section)
+            for key, val_list in sect.iteritems():
+                # every value is also a list
+                for v in val_list:
+                    key_val = key
+                    if v is not None:
+                        key_val += " = " + str(v)
+                        file.write("%s\n" % (key_val))
+            file.write("\n")
 
 ###############################################################################
 
-COMMENT = ';'
-DEFAULTSECT = 'general'
-
 class MultiOrderedConfigParser:
-    def __init__(self):
-        self._default = MultiOrderedDict()
-        # sections contain dictionaries of dictionaries
+    def __init__(self, parent=None):
+        self._parent = parent
+        self._defaults = MultiOrderedDict()
         self._sections = MultiOrderedDict()
-
-    def default(self):
-        return self._default
+        self._includes = OrderedDict()
+
+    def defaults(self):
+        return self._defaults
+
+    def default(self, key):
+        """Retrieves a list of dictionaries for a default section."""
+        return get_defaults(self, key)
+
+    def add_default(self, key, template_keys=None):
+        """Adds a default section to defaults, returning the
+           default Section object.
+        """
+        if template_keys is None:
+            template_keys = []
+        return self.add_section(key, template_keys, self._defaults)
 
     def sections(self):
         return self._sections
 
-    def section(self, section, index=-1):
-        """Retrieves a section dictionary for the given section. If the section
-           holds only a single section dictionary return that dictionary. If
-           the section holds more than one dictionary and an index is given
-           that is greater than or equal to zero then return the dictionary at
-           the index. Otherwise return the list of dictionaries for the given
-           section name."""
-        try:
-            return get_value(self._sections, section, index)
+    def section(self, key):
+        """Retrieves a list of dictionaries for a section."""
+        return get_sections(self, key)
+
+    def add_section(self, key, template_keys=None, mdicts=None):
+        if template_keys is None:
+            template_keys = []
+        if mdicts is None:
+            mdicts = self._sections
+        res = Section()
+        for t in template_keys:
+            res.add_templates(get_defaults(self, t))
+        res.add_defaults(get_defaults(self, DEFAULTSECT))
+        mdicts.insert(0, key, res)
+        return res
+
+    def includes(self):
+        return self._includes
+
+    def add_include(self, filename, parser=None):
+        if filename in self._includes:
+            return self._includes[filename]
+
+        self._includes[filename] = res = \
+             MultiOrderedConfigParser(self) if parser is None else parser
+        return res;
+
+    def get(self, section, key):
+        """Retrieves the list of values from a section for a key."""
+        try:
+            # search for the value in the list of sections
+            return find_value(self.section(section), key)
         except KeyError:
-            raise LookupError("section %r not found" % section)
-
-    def add_section(self, section, defaults=[]):
-        """Adds a section with the given name and defaults."""
-        self._sections[section] = res = Section(defaults)
-        return res
-
-    def get(self, key, section=DEFAULTSECT, index=-1):
-        """Retrieves a value for the given key from the given section. If the
-           key only holds a single value return that value. If the key holds
-           more than one value and an index is given that is greater than or
-           equal to zero then return the value at the index. Otherwise return
-           the list of values."""
-        try:
-            if section == DEFAULTSECT:
-                return get_value(self._default, key, index)
-
-            # search section(s)
-            return find_value(self.section(section), key, index)
+            pass
+
+        try:
+            # section may be a default section so, search
+            # for the value in the list of defaults
+            return find_value(self.default(section), key)
         except KeyError:
-            # check default section if we haven't already
-            if section != DEFAULTSECT:
-                return self.get(key, DEFAULTSECT, index)
-            raise LookupError("key %r not found in section %r"
+            raise LookupError("key %r not found for section %r"
                               % (key, section))
 
-    def set(self, key, val, section=DEFAULTSECT):
+    def set(self, section, key, val):
         """Sets an option in the given section."""
-        if section == DEFAULTSECT:
-            self._default[key] = val
+        # TODO - set in multiple sections? (for now set in first)
+        # TODO - set in both sections and defaults?
+        if section in self._sections:
+            self.section(section)[0][key] = val
         else:
-            # for now only set value in first section
-            self.section(section, 0)[key] = val
+            self.defaults(section)[0][key] = val
 
     def read(self, filename):
         try:
@@ -198,45 +353,42 @@
             print "Could not open file ", filename, " for reading"
 
     def _read(self, file, filename):
+        is_comment = False # used for multi-lined comments
         for line in file:
-            line = remove_comment(line)
+            line, is_comment = remove_comment(line, is_comment)
             if not line:
                 # line was empty or was a comment
                 continue
 
-            section = try_section(line)
+            include_name = try_include(line)
+            if include_name:
+                parser = self.add_include(include_name)
+                parser.read(include_name)
+                continue
+
+            section, is_template, templates = try_section(line)
             if section:
-                if section == DEFAULTSECT:
-                    sect = self._default
+                if section == DEFAULTSECT or is_template:
+                    sect = self.add_default(section, templates)
                 else:
-                    self._sections[section] = sect = Section([self._default])
-                    # TODO - if section has templates add those
-                    #        with sect.add_default
+                    sect = self.add_section(section, templates)
                 continue
 
             key, val = try_option(line)
             sect[key] = val
 
-    def write(self, filename):
-        try:
-            with open(filename, 'wt') as file:
-                self._write(file)
-        except IOError:
-            print "Could not open file ", filename, " for writing"
-        pass
-
-    def _write(self, file):
-        # TODO - need to write out default section, but right now in
-        #        our case res_sip.conf has not default/general section
-        for section, sect_list in self._sections.iteritems():
-            # every section contains a list of dictionaries
-            for sect in sect_list:
-                file.write("[%s]\n" % section)
-                for key, val_list in sect.iteritems():
-                    # every value is also a list
-                    for v in val_list:
-                        key_val = key
-                        if (v is not None):
-                            key_val += " = " + str(v)
-                        file.write("%s\n" % (key_val))
-                file.write("\n")
+    def write(self, f):
+        try:
+            for key, val in self._includes.iteritems():
+                val.write(key)
+                f.write('#include "%s"\n' % key)
+
+            f.write('\n')
+            write_dicts(f, self._defaults)
+            write_dicts(f, self._sections)
+        except:
+            try:
+                with open(f, 'wt') as fp:
+                    self.write(fp)
+            except IOError:
+                print "Could not open file ", f, " for writing"

Modified: team/dlee/ASTERISK-22296/contrib/scripts/sip_to_res_sip/astdicts.py
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ASTERISK-22296/contrib/scripts/sip_to_res_sip/astdicts.py?view=diff&rev=397678&r1=397677&r2=397678
==============================================================================
--- team/dlee/ASTERISK-22296/contrib/scripts/sip_to_res_sip/astdicts.py (original)
+++ team/dlee/ASTERISK-22296/contrib/scripts/sip_to_res_sip/astdicts.py Mon Aug 26 16:58:57 2013
@@ -265,11 +265,28 @@
     def __init__(self, *args, **kwds):
         OrderedDict.__init__(self, *args, **kwds)
 
-    def __setitem__(self, key, val):
+    def __setitem__(self, key, val, i=None):
         if key not in self:
-            OrderedDict.__setitem__(self, key, [val])
-        elif val not in self[key]:
-            self[key].append(val)
+#            print "__setitem__ key = ", key, " val = ", val
+            OrderedDict.__setitem__(
+                self, key, val if isinstance(val, list) else [val])
+            return
+#        print "inserting key = ", key, " val = ", val
+        vals = self[key]
+        if i is None:
+            i = len(vals)
+
+        if not isinstance(val, list):
+            if val not in vals:
+                vals.insert(i, val)
+        else:
+            for j in val.reverse():
+                if j not in vals:
+                    vals.insert(i, j)
+
+
+    def insert(self, i, key, val):
+        self.__setitem__(key, val, i)
 
     def copy(self):
         # TODO - find out why for some reason copies
@@ -279,28 +296,3 @@
             for v in val:
                 c[key] = v
         return c
-
-    # def update(self, other=None, **kwds):
-    #     if other is None:
-    #         pass
-
-    #     if isinstance(other, list):
-    #         for val in other:
-    #             update(self, val)
-    #         return
-
-    #     for key, val in other.iteritems():
-    #         # key = [ v1, v2, ...n ]
-    #         if key in self and len(self[key]) > 1:
-    #             # merge values adding only those not already in list
-    #             val = self[key] + [v for v in val if v not in self[key]]
-    #         OrderedDict.__setitem__(self, key, val)
-    #     # if hasattr(other, 'keys'):
-    #     #         other = other.keys()
-    #     # for (key, val) in obj.iteritems():
-    #     #     if key in self and len(self[key]) > 1:
-    #     #         # add only values not already in list
-    #     #         val = self[key] + [v for v in val if v not in self[key]]
-    #     #     OrderedDict.__setitem__(self, key, val)
-    #     if kwds:
-    #         self.update(kwds)

Modified: team/dlee/ASTERISK-22296/contrib/scripts/sip_to_res_sip/sip_to_res_sip.py
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ASTERISK-22296/contrib/scripts/sip_to_res_sip/sip_to_res_sip.py?view=diff&rev=397678&r1=397677&r2=397678
==============================================================================
--- team/dlee/ASTERISK-22296/contrib/scripts/sip_to_res_sip/sip_to_res_sip.py (original)
+++ team/dlee/ASTERISK-22296/contrib/scripts/sip_to_res_sip/sip_to_res_sip.py Mon Aug 26 16:58:57 2013
@@ -1,17 +1,24 @@
 #!/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
 
-# configuration parser for sip.conf
-sip = astconfigparser.MultiOrderedConfigParser()
-
-# configuration writer for res_sip.conf
-res_sip = astconfigparser.MultiOrderedConfigParser()
+PREFIX = 'res_sip_'
 
 ###############################################################################
 ### some utility functions
 ###############################################################################
-def section_by_type(section, type='endpoint'):
+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(
@@ -22,10 +29,11 @@
         sect['type'] = type
         return sect
 
-def set_value(key=None, val=None, section=None, type='endpoint'):
+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):
-        set_value(key if key else k, v, s, type)
+    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
@@ -33,135 +41,151 @@
         return _set_value
 
     # otherwise try to set the value
-    section_by_type(section, type)[key] = val
-
-def merge_value(key=None, val=None, section=None,
-                type='endpoint', section_to=None):
+    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):
-        merge_value(key if key else k, v, s, type, section_to)
+    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 single section
-    sect = sip.section(section)
+    # 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, type)
+        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):
+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':
-        print "sip.conf: dtmfmode = %s did not fully map into " \
-              "res_sip.conf - setting to 'none'" % val
+        nmapped(section, key, val + " ; did not fully map - set to none")
         val = 'none'
-    set_value(key, val, section)
-
-def from_nat(key, val, section):
+    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)
-        set_value('rewrite_contact', 'yes', section)
+        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)
+        set_value('rtp_symmetric', 'yes', section, res_sip, nmapped)
     if is_in(val, 'force_rport'):
-        set_value('force_rport', 'yes', section)
-        set_value('rewrite_contact', 'yes', section)
-

[... 2285 lines stripped ...]



More information about the asterisk-commits mailing list