3from __future__ 
import print_function
 
    9    from urllib.parse 
import urlparse
 
   11    from urlparse 
import urlparse 
 
   24    """Finds a section based upon the given type, adding it if not found.""" 
   25    def __find_dict(mdicts, key, val):
 
   26        """Given a list of multi-dicts, return the multi-dict that contains 
   27           the given key/value pair.""" 
   30            return key 
in d 
and val 
in d[key]
 
   33            return [d 
for d 
in mdicts 
if found(d)][0]
 
   35            raise LookupError(
"Dictionary not located for key = %s, value = %s" 
   39        return __find_dict(pjsip.section(section), 
'type', type)
 
   42        sect = pjsip.add_section(section)
 
 
   47def ignore(key=None, val=None, section=None, pjsip=None,
 
   48           nmapped=None, type='endpoint'):
 
   49    """Ignore a key and mark it as mapped""" 
 
   52def set_value(key=None, val=None, section=None, pjsip=None,
 
   53              nmapped=None, type='endpoint'):
 
   54    """Sets the key to the value within the section in pjsip.conf""" 
   55    def _set_value(k, v, s, r, n):
 
   56        set_value(key 
if key 
else k, v, s, r, n, type)
 
   60    if not val 
and not section:
 
   65        val[0] 
if isinstance(val, list) 
else val
 
 
   69                nmapped=None, type='endpoint', section_to=None,
 
   71    """Merge values from the given section with those from the default.""" 
   72    def _merge_value(k, v, s, r, n):
 
   73        merge_value(key 
if key 
else k, v, s, r, n, type, section_to, key_to)
 
   77    if not val 
and not section:
 
   82        sect = sip.section(section)[0]
 
   84        sect = sip.default(section)[0]
 
   86    for i 
in sect.get_merged(key):
 
   88                  section_to 
if section_to 
else section,
 
 
   92                nmapped=None, type='endpoint', section_to=None,
 
   94    """Merge values from allow/deny with those from the default. Special treatment for all""" 
   95    def _merge_codec_value(k, v, s, r, n):
 
  100    if not val 
and not section:
 
  101        return _merge_codec_value
 
  105            disallow = sip.get(section, 
'disallow')[0]
 
  106            if disallow == 
'all':
 
  108                for i 
in sip.get(section, 
'allow'):
 
  109                    set_value(key, i, section, pjsip, nmapped, type)
 
  111                merge_value(key, val, section, pjsip, nmapped, type, section_to, key_to)
 
  113            print(
"lookup error", file=sys.stderr)
 
  114            merge_value(key, val, section, pjsip, nmapped, type, section_to, key_to)
 
  116    elif key == 
'disallow':
 
  118            allow = sip.get(section, 
'allow')[0]
 
  121                for i 
in sip.get(section, 
'disallow'):
 
  122                    set_value(key, i, section, pjsip, nmapped, type)
 
  124                merge_value(key, val, section, pjsip, nmapped, type, section_to, key_to)
 
  126            merge_value(key, val, section, pjsip, nmapped, type, section_to, key_to)
 
  129        merge_value(key, val, section, pjsip, nmapped, type, section_to, key_to)
 
 
  133    """Write non-mapped sip.conf values to the non-mapped object""" 
  134    def _non_mapped(section, key, val):
 
  135        """Writes a non-mapped value from sip.conf to the non-mapped object.""" 
  136        if section 
not in nmapped:
 
  138            if isinstance(val, list):
 
  142                    nmapped[section][0][key] = v
 
  144                nmapped[section][0][key] = val
 
 
  156    Sets the dtmfmode value.  If value matches allowable option in pjsip 
  157    then map it, otherwise set it to none. 
  161    if val == 
'inband' or val == 
'info' or val == 
'auto':
 
  162        set_value(key, val, section, pjsip, nmapped)
 
  163    elif val == 
'rfc2833':
 
  164        set_value(key, 
'rfc4733', section, pjsip, nmapped)
 
  166        nmapped(section, key, val + 
" ; did not fully map - set to none")
 
  167        set_value(key, 
'none', section, pjsip, nmapped)
 
 
  171    """Sets values from udptl into the appropriate pjsip.conf options.""" 
  173        val = sip.get(section, 
't38pt_udptl')[0]
 
  176            val = sip.get(
'general', 
't38pt_udptl')[0]
 
  182        set_value(
't38_udptl', 
'yes', section, pjsip, nmapped)
 
  184        set_value(
't38_udptl', 
'no', section, pjsip, nmapped)
 
  185    if 'redundancy' in val:
 
  189    set_value(
't38_udptl_ec', ec, section, pjsip, nmapped)
 
 
  192    """Sets values from nat into the appropriate pjsip.conf options.""" 
  196        set_value(
'rtp_symmetric', 
'yes', section, pjsip, nmapped)
 
  197        set_value(
'rewrite_contact', 
'yes', section, pjsip, nmapped)
 
  199        set_value(
'rtp_symmetric', 
'yes', section, pjsip, nmapped)
 
  200    if 'force_rport' in val:
 
  201        set_value(
'force_rport', 
'yes', section, pjsip, nmapped)
 
  202        set_value(
'rewrite_contact', 
'yes', section, pjsip, nmapped)
 
 
  207    Sets the timers in pjsip.conf from the session-timers option 
  216    if val == 
'originate':
 
  217        set_value(
'timers', 
'always', section, pjsip, nmapped)
 
  218    elif val == 
'refuse':
 
  219        set_value(
'timers', 
'no', section, pjsip, nmapped)
 
  221        set_value(
'timers', 
'yes', section, pjsip, nmapped)
 
 
  226    Maps values from the sip.conf comma separated direct_media option 
  227    into pjsip.conf direct_media options. 
  230        set_value(
'direct_media', 
'yes', section, pjsip, nmapped)
 
  232        set_value(
'direct_media_method', 
'update', section, pjsip, nmapped)
 
  233    if 'outgoing' in val:
 
  234        set_value(
'directed_media_glare_mitigation', 
'outgoing', section,
 
  237        set_value(
'disable_directed_media_on_nat', 
'yes', section, pjsip,
 
  240        set_value(
'direct_media', 
'no', section, pjsip, nmapped)
 
 
  244    """Sets the send_rpid/pai values in pjsip.conf.""" 
  245    if val == 
'yes' or val == 
'rpid':
 
  246        set_value(
'send_rpid', 
'yes', section, pjsip, nmapped)
 
  248        set_value(
'send_pai', 
'yes', section, pjsip, nmapped)
 
 
  252    """Sets the media_encryption value in pjsip.conf""" 
  254        dtls = sip.get(section, 
'dtlsenable')[0]
 
  262        set_value(
'media_encryption', 
'sdes', section, pjsip, nmapped)
 
 
  267    If record on/off feature is set to automixmon then set 
  268    one_touch_recording, otherwise it can't be mapped. 
  270    set_value(
'one_touch_recording', 
'yes', section, pjsip, nmapped)
 
  271    set_value(key, val, section, pjsip, nmapped)
 
 
  274    """Sets the record_on_feature in pjsip.conf""" 
 
  278    """Sets the record_off_feature in pjsip.conf""" 
 
  282    """Sets the inband_progress value in pjsip.conf""" 
  286    set_value(
'inband_progress', val, section, pjsip, nmapped)
 
 
  289def build_host(config, host, section='general', port_key=None):
 
  291    Returns a string composed of a host:port. This assumes that the host 
  292    may have a port as part of the initial value. The port_key overrides 
  293    a port in host, see parameter 'bindport' in chan_sip. 
  296        socket.inet_pton(socket.AF_INET6, host)
 
  297        if not host.startswith(
'['):
 
  299            host = 
'[' + host + 
']' 
  305    url = urlparse(
'sip://' + host)
 
  309            port = config.get(section, port_key)[0]
 
  312                socket.inet_pton(socket.AF_INET6, host)
 
  313                if not host.startswith(
'['):
 
  315                    host = 
'[' + host + 
']' 
  318            return host + 
':' + port
 
 
  329    Sets contact info in an AOR section in pjsip.conf using 'host' 
  330    and 'port' data from sip.conf 
  334    set_value(
'aors', section, section, pjsip, nmapped)
 
  337        set_value(
'max_contacts', 1, section, pjsip, nmapped, 
'aor')
 
  349        user = sip.multi_get(section, [
'defaultuser', 
'username'])[0]
 
  355    result += 
build_host(sip, val, section, 
'port')
 
  357    set_value(
'contact', result, section, pjsip, nmapped, 
'aor')
 
 
  362    Determines whether a mailbox configured in sip.conf should map to 
  363    an endpoint or aor in pjsip.conf. If subscribemwi is true, then the 
  364    mailboxes are set on an aor. Otherwise the mailboxes are set on the 
  369        subscribemwi = sip.get(section, 
'subscribemwi')[0]
 
  374    set_value(
'mailboxes', val, section, pjsip, nmapped, 
'aor' 
  375              if subscribemwi == 
'yes' else 'endpoint')
 
 
  380    Sets up authentication information for a specific endpoint based on the 
  381    'secret' setting on a peer in sip.conf 
  383    set_value(
'username', section, section, pjsip, nmapped, 
'auth')
 
  391        set_value(
'password', val, section, pjsip, nmapped, 
'auth')
 
  393        set_value(
'md5_cred', val, section, pjsip, nmapped, 
'auth')
 
  394        set_value(
'auth_type', 
'md5', section, pjsip, nmapped, 
'auth')
 
  398        auths = sip.get(
'authentication', 
'auth')
 
  400            user, at, realm = i.partition(
'@')
 
  405    realm_str = 
','.join(realms)
 
  407    set_value(
'auth', section, section, pjsip, nmapped)
 
  408    set_value(
'outbound_auth', realm_str, section, pjsip, nmapped)
 
 
  413    Examines the 'type' field for a sip.conf peer and creates an identify 
  414    section if the type is either 'peer' or 'friend'. The identify section uses 
  415    either the host or defaultip field of the sip.conf peer. 
  417    if val != 
'peer' and val != 
'friend':
 
  421        ip = sip.get(section, 
'host')[0]
 
  427            ip = sip.get(section, 
'defaultip')[0]
 
  431    set_value(
'endpoint', section, section, pjsip, nmapped, 
'identify')
 
  432    set_value(
'match', ip, section, pjsip, nmapped, 
'identify')
 
 
  436    """Sets the srtp_tag32 option based on sip.conf encryption_taglen""" 
  438        set_value(
'srtp_tag_32', 
'yes', section, pjsip, nmapped)
 
 
  442    """Optionally sets media_encryption=dtls based on sip.conf dtlsenable""" 
  444        set_value(
'media_encryption', 
'dtls', section, pjsip, nmapped)
 
 
  455    [
'context',            set_value],
 
  456    [
'dtmfmode',           set_dtmfmode],
 
  457    [
'disallow',           merge_codec_value],
 
  458    [
'allow',              merge_codec_value],
 
  461    [
'rtptimeout',         
set_value(
'rtp_timeout')],
 
  462    [
'icesupport',         
set_value(
'ice_support')],
 
  464    [
'outboundproxy',      
set_value(
'outbound_proxy')],
 
  465    [
'mohsuggest',         
set_value(
'moh_suggest')],
 
  466    [
'session-timers',     set_timers],          
 
  467    [
'session-minse',      
set_value(
'timers_min_se')],
 
  468    [
'session-expires',    
set_value(
'timers_sess_expires')],
 
  470    [
'canreinvite',        set_direct_media],    
 
  471    [
'directmedia',        set_direct_media],    
 
  475    [
'callerid',           set_value],           
 
  476    [
'callingpres',        
set_value(
'callerid_privacy')],
 
  478    [
'trustrpid',          
set_value(
'trust_id_inbound')],
 
  479    [
'sendrpid',           from_sendrpid],       
 
  480    [
'send_diversion',     set_value],
 
  481    [
'encryption',         set_media_encryption],
 
  483    [
'recordonfeature',    set_record_on_feature],  
 
  484    [
'recordofffeature',   set_record_off_feature],  
 
  485    [
'progressinband',     from_progressinband], 
 
  487    [
'pickupgroup',        
set_value(
'pickup_group')],
 
  488    [
'namedcallgroup',     
set_value(
'named_call_group')],
 
  489    [
'namedpickupgroup',   
set_value(
'named_pickup_group')],
 
  490    [
'allowtransfer',      
set_value(
'allow_transfer')],
 
  492    [
'fromdomain',         
set_value(
'from_domain')],
 
  494    [
'tos_audio',          set_value],
 
  495    [
'tos_video',          set_value],
 
  496    [
'cos_audio',          set_value],
 
  497    [
'cos_video',          set_value],
 
  499    [
'sdpsession',         
set_value(
'sdp_session')],
 
  501    [
'language',           set_value],
 
  502    [
'allowsubscribe',     
set_value(
'allow_subscribe')],
 
  503    [
'subscribecontext',   
set_value(
'subscribe_context')],
 
  504    [
'subminexpiry',       
set_value(
'sub_min_expiry')],
 
  505    [
'rtp_engine',         set_value],
 
  506    [
'mailbox',            from_mailbox],
 
  507    [
'busylevel',          
set_value(
'device_state_busy_at')],
 
  508    [
'secret',             setup_auth],
 
  509    [
'md5secret',          setup_auth],
 
  510    [
'type',               setup_ident],
 
  511    [
'dtlsenable',         from_dtlsenable],
 
  512    [
'dtlsverify',         
set_value(
'dtls_verify')],
 
  514    [
'dtlscertfile',       
set_value(
'dtls_cert_file')],
 
  515    [
'dtlsprivatekey',     
set_value(
'dtls_private_key')],
 
  516    [
'dtlscipher',         
set_value(
'dtls_cipher')],
 
  517    [
'dtlscafile',         
set_value(
'dtls_ca_file')],
 
  518    [
'dtlscapath',         
set_value(
'dtls_ca_path')],
 
  520    [
'encryption_taglen',  from_encryption_taglen],
 
  526    [
'qualifyfreq',        
set_value(
'qualify_frequency', type=
'aor')],
 
  527    [
'maxexpiry',          
set_value(
'maximum_expiration', type=
'aor')],
 
  528    [
'minexpiry',          
set_value(
'minimum_expiration', type=
'aor')],
 
  529    [
'defaultexpiry',      
set_value(
'default_expiration', type=
'aor')],
 
  541    [
'permit',             
merge_value(type=
'acl', section_to=
'acl')],
 
  542    [
'deny',               
merge_value(type=
'acl', section_to=
'acl')],
 
  543    [
'acl',                
merge_value(type=
'acl', section_to=
'acl')],
 
  544    [
'contactpermit',      
merge_value(type=
'acl', section_to=
'acl', key_to=
'contact_permit')],
 
  545    [
'contactdeny',        
merge_value(type=
'acl', section_to=
'acl', key_to=
'contact_deny')],
 
  546    [
'contactacl',         
merge_value(type=
'acl', section_to=
'acl', key_to=
'contact_acl')],
 
  592    Given an address in the form 'host:port' separate the host and port 
  594    Returns a two-tuple of strings, (host, port). If no port is present in the 
  595    string, then the port section of the tuple is None. 
  598        socket.inet_pton(socket.AF_INET6, addr)
 
  599        if not addr.startswith(
'['):
 
  606    url = urlparse(
'sip://' + addr)
 
  608    return (url.hostname, url.port)
 
 
  613    sip.conf has several global settings that in pjsip.conf apply to individual 
  614    transports. This function adds these global settings to each individual 
  617    The settings included are: 
  618    externaddr (or externip) 
  620    externtcpport for TCP 
  621    externtlsport for TLS 
  627        extern_addr = sip.multi_get(
'general', [
'externaddr', 
'externip',
 
  631            port = sip.get(
'general', 
'extern' + protocol + 
'port')[0]
 
  634        set_value(
'external_media_address', host, section, pjsip,
 
  635                  nmapped, 
'transport')
 
  636        set_value(
'external_signaling_address', host, section, pjsip,
 
  637                  nmapped, 
'transport')
 
  639            set_value(
'external_signaling_port', port, section, pjsip,
 
  640                      nmapped, 
'transport')
 
  645        merge_value(
'localnet', sip.get(
'general', 
'localnet')[0], 
'general',
 
  646                    pjsip, nmapped, 
'transport', section, 
"local_net")
 
  652        set_value(
'tos', sip.get(
'general', 
'tos_sip')[0], section, pjsip,
 
  653                  nmapped, 
'transport')
 
  658        set_value(
'cos', sip.get(
'general', 
'cos_sip')[0], section, pjsip,
 
  659                  nmapped, 
'transport')
 
 
  666    Given the protocol (udp, tcp, or tls), return 
  667    - the bind address, like [::] or 0.0.0.0 
  668    - name of the section to be created 
  670    section = 
'transport-' + protocol
 
  673    if protocol != 
'udp':
 
  675            enabled = sip.get(
'general', protocol + 
'enable')[0]
 
  678            return (
None, section)
 
  680            return (
None, section)
 
  683        bind = pjsip.get(section, 
'bind')[0]
 
  686        return (
None, section)
 
  691        bind = pjsip.get(section + 
'6', 
'bind')[0]
 
  698            bind += 
':' + 
str(port)
 
  702            bind = sip.get(
'general', protocol + 
'bindaddr')[0]
 
  704            if protocol == 
'udp':
 
  706                    bind = sip.get(
'general', 
'bindaddr')[0]
 
  711                    bind = pjsip.get(
'transport-udp6', 
'bind')[0]
 
  713                    bind = pjsip.get(
'transport-udp', 
'bind')[0]
 
  715                if protocol == 
'tls':
 
  721    if protocol == 
'udp':
 
  722        host = 
build_host(sip, bind, 
'general', 
'bindport')
 
  726    return (host, section)
 
 
  731    Creates a 'transport-udp' section in the pjsip.conf file based 
  732    on the following settings from sip.conf: 
  734    bindaddr (or udpbindaddr) 
  738    bind, section = 
get_bind(sip, pjsip, protocol)
 
  740    set_value(
'protocol', protocol, section, pjsip, nmapped, 
'transport')
 
  741    set_value(
'bind', bind, section, pjsip, nmapped, 
'transport')
 
 
  747    Creates a 'transport-tcp' section in the pjsip.conf file based 
  748    on the following settings from sip.conf: 
  751    tcpbindaddr (or bindaddr) 
  754    bind, section = 
get_bind(sip, pjsip, protocol)
 
  758    set_value(
'protocol', protocol, section, pjsip, nmapped, 
'transport')
 
  759    set_value(
'bind', bind, section, pjsip, nmapped, 
'transport')
 
 
  764    """Sets cert_file based on sip.conf tlscertfile""" 
  765    set_value(
'cert_file', val, section, pjsip, nmapped,
 
 
  770    """Sets privkey_file based on sip.conf tlsprivatekey or sslprivatekey""" 
  771    set_value(
'priv_key_file', val, section, pjsip, nmapped,
 
 
  776    """Sets cipher based on sip.conf tlscipher or sslcipher""" 
  779    print('chan_sip ciphers do not match 1:1 with PJSIP ciphers.' \ 
  780          ' You should manually review and adjust this.', file=sys.stderr) 
  782    set_value('cipher', val, section, pjsip, nmapped, 'transport') 
 
  785def set_tls_cafile(val, pjsip, section, nmapped): 
  786    """Sets ca_list_file based on sip.conf tlscafile"""
 
  787    set_value('ca_list_file', val, section, pjsip, nmapped,
 
 
  791def set_tls_capath(val, pjsip, section, nmapped):
 
  792    """Sets ca_list_path based on sip.conf tlscapath"""
 
  793    set_value('ca_list_path', val, section, pjsip, nmapped,
 
 
  797def set_tls_verifyclient(val, pjsip, section, nmapped):
 
  798    """Sets verify_client based on sip.conf tlsverifyclient"""
 
  799    set_value('verify_client', val, section, pjsip, nmapped,
 
 
  803def set_tls_verifyserver(val, pjsip, section, nmapped):
 
  804    """Sets verify_server based on sip.conf tlsdontverifyserve
r""" 
  807        set_value('verify_server', 'yes', section, pjsip, nmapped, 
  810        set_value('verify_server', 'no', section, pjsip, nmapped, 
 
  814def create_tls(sip, pjsip, nmapped): 
  816    Creates a 'transport-tls' section in pjsip.conf based on the following
 
  817    settings from sip.conf:
 
  819    tlsenable (or sslenable)
 
  820    tlsbindaddr (or sslbindaddr or bindaddr)
 
  821    tlsprivatekey (or sslprivatekey)
 
  822    tlscipher (or sslcipher)
 
  824    tlscapath (or tlscadir)
 
  825    tlscertfile (or sslcert or tlscert)
 
  828    tlsclientmethod (or sslclientmethod)
 
  831    bind, section = get_bind(sip, pjsip, protocol)
 
  835    set_value('protocol', protocol, section, pjsip, nmapped, 'transport')
 
  836    set_value('bind', bind, section, pjsip, nmapped, 'transport')
 
  837    set_transport_common(section, sip, pjsip, protocol, nmapped)
 
  840        (['tlscertfile', 'sslcert', 'tlscert'], set_tls_cert_file),
 
  841        (['tlsprivatekey', 'sslprivatekey'], set_tls_private_key),
 
  842        (['tlscipher', 'sslcipher'], set_tls_cipher),
 
  843        (['tlscafile'], set_tls_cafile),
 
  844        (['tlscapath', 'tlscadir'], set_tls_capath),
 
  845        (['tlsverifyclient'], set_tls_verifyclient),
 
  846        (['tlsdontverifyserver'], set_tls_verifyserver)
 
  851            i[1](sip.multi_get('general', i[0])[0], pjsip, section, nmapped)
 
  856        method = sip.multi_get('general', ['tlsclientmethod',
 
  857                                           'sslclientmethod'])[0]
 
  858        if section != 'transport-' + protocol + '6':  # print only once
 
  859            print('In chan_sip, you specified the TLS version. With chan_sip,' \
 
  860                  ' this was just for outbound client connections. In' \
 
  861                  ' chan_pjsip, this value is for client and server. Instead,' \
 
  862                  ' consider not to specify \'tlsclientmethod\' for chan_sip' \
 
  863                  ' and \'method = sslv23\' for chan_pjsip.', file=sys.stderr)
 
  866        OpenSSL emerged during the 90s. SSLv2 and SSLv3 were the only
 
  867        existing methods at that time. The OpenSSL project continued. And as
 
  868        of today (OpenSSL 1.0.2) this does not start SSLv2 and SSLv3 anymore
 
  869        but TLSv1.0 and v1.2. Or stated differently: This method should
 
  870        have been called 'method = secure' or 'method = automatic' back in
 
  871        the 90s. The PJProject did not realize this and uses 'tlsv1' as
 
  872        default when unspecified, which disables TLSv1.2. chan_sip used
 
  873        'sslv23' as default when unspecified, which gives TLSv1.0 and v1.2.
 
  876    set_value('method', method, section, pjsip, nmapped, 'transport')
 
 
  879def map_transports(sip, pjsip, nmapped):
 
  881    Finds options in sip.conf general section pertaining to
 
  882    transport configuration and creates appropriate transport
 
  883    configuration sections in pjsip.conf.
 
  885    sip.conf only allows a single UDP transport, TCP transport,
 
  886    and TLS transport for each IP version. As such, the mapping
 
  887    into PJSIP can be made consistent by defining six sections:
 
  896    To accommodate the default behaviors in sip.conf, we'll need to
 
  897    create the UDP transports first, followed by the TCP and TLS transports.
 
  900    # First create a UDP transport. Even if no bind parameters were provided
 
  901    # in sip.conf, chan_sip would always bind to UDP 0.0.0.0:5060
 
  902    create_udp(sip, pjsip, nmapped)
 
  903    create_udp(sip, pjsip, nmapped)
 
  905    # TCP settings may be dependent on UDP settings, so do it second.
 
  906    create_tcp(sip, pjsip, nmapped)
 
  907    create_tcp(sip, pjsip, nmapped)
 
  908    create_tls(sip, pjsip, nmapped)
 
  909    create_tls(sip, pjsip, nmapped)
 
 
  912def map_auth(sip, pjsip, nmapped):
 
  914    Creates auth sections based on entries in the authentication section of
 
  915    sip.conf. pjsip.conf section names consist of "auth_" followed by the name
 
  919        auths = sip.get('authentication', 'auth')
 
  924        creds, at, realm = i.partition('@')
 
  925        if not at and not realm:
 
  928        user, colon, secret = creds.partition(':')
 
  930            user, sharp, md5 = creds.partition('#')
 
  934        section = "auth_" + realm
 
  936        set_value('realm', realm, section, pjsip, nmapped, 'auth')
 
  937        set_value('username', user, section, pjsip, nmapped, 'auth')
 
  939            set_value('password', secret, section, pjsip, nmapped, 'auth')
 
  941            set_value('md5_cred', md5, section, pjsip, nmapped, 'auth')
 
  942            set_value('auth_type', 'md5', section, pjsip, nmapped, 'auth')
 
 
  947    Class for parsing and storing information in a register line in sip.conf.
 
  949    def __init__(self, line, retry_interval, max_attempts, outbound_proxy):
 
  950        self.retry_interval = retry_interval
 
  951        self.max_attempts = max_attempts
 
  952        self.outbound_proxy = outbound_proxy
 
 
  955    def parse(self, line):
 
  957        Initial parsing routine for register lines in sip.conf.
 
  959        This splits the line into the part before the host, and the part
 
  960        after the '@' symbol. These two parts are then passed to their
 
  965        # [peer?][transport://]user[@domain][:secret[:authuser]]@host[:port][/extension][~expiry]
 
  967        prehost, at, host_part = line.rpartition('@')
 
  971        self.parse_host_part(host_part)
 
  972        self.parse_user_part(prehost)
 
 
  974    def parse_host_part(self, host_part):
 
  976        Parsing routine for the part after the final '@' in a register line.
 
  977        The strategy is to use partition calls to peel away the data starting
 
  978        from the right and working to the left.
 
  980        pre_expiry, sep, expiry = host_part.partition('~')
 
  981        pre_extension, sep, self.extension = pre_expiry.partition('/')
 
  982        self.host, sep, self.port = pre_extension.partition(':')
 
  984        self.expiry = expiry if expiry else '120'
 
 
  986    def parse_user_part(self, user_part):
 
  988        Parsing routine for the part before the final '@' in a register line.
 
  989        The only mandatory part of this line is the user portion. The strategy
 
  990        here is to start by using partition calls to remove everything to
 
  991        the right of the user, then finish by using rpartition calls to remove
 
  992        everything to the left of the user.
 
  995        self.protocol = 'udp'
 
  996        protocols = ['udp', 'tcp', 'tls']
 
  997        for protocol in protocols:
 
  998            position = user_part.find(protocol + '://')
 
 1000                post_transport = user_part[position + 6:]
 
 1001                self.peer, sep, self.protocol = user_part[:position + 3].rpartition('?')
 
 1002                user_part = post_transport
 
 1005        colons = user_part.count(':')
 
 1007            # :domainport:secret:authuser
 
 1008            pre_auth, sep, port_auth = user_part.partition(':')
 
 1009            self.domainport, sep, auth = port_auth.partition(':')
 
 1010            self.secret, sep, self.authuser = auth.partition(':')
 
 1013            pre_auth, sep, auth = user_part.partition(':')
 
 1014            self.secret, sep, self.authuser = auth.partition(':')
 
 1017            pre_auth, sep, self.secret = user_part.partition(':')
 
 1019            # No port, secret, or authuser
 
 1020            pre_auth = user_part
 
 1025        self.user, sep, self.domain = pre_auth.partition('@')
 
 
 1027    def write(self, pjsip, nmapped):
 
 1029        Write parsed registration data into a section in pjsip.conf
 
 1031        Most of the data in self will get written to a registration section.
 
 1032        However, there will also need to be an auth section created if a
 
 1033        secret or authuser is present.
 
 1035        General mapping of values:
 
 1036        A combination of self.host and self.port is server_uri
 
 1037        A combination of self.user, self.domain, and self.domainport is
 
 1039        self.expiry is expiration
 
 1040        self.extension is contact_user
 
 1041        self.protocol will map to one of the mapped transports
 
 1042        self.secret and self.authuser will result in a new auth section, and
 
 1043          outbound_auth will point to that section.
 
 1044        XXX self.peer really doesn't map to anything :(
 
 1047        section = 'reg_' + self.host
 
 1049        set_value('retry_interval', self.retry_interval, section, pjsip,
 
 1050                  nmapped, 'registration')
 
 1051        set_value('max_retries', self.max_attempts, section, pjsip, nmapped,
 
 1054            set_value('contact_user', self.extension, section, pjsip, nmapped,
 
 1057        set_value('expiration', self.expiry, section, pjsip, nmapped,
 
 1060        if self.protocol == 'udp':
 
 1061            set_value('transport', 'transport-udp', section, pjsip, nmapped,
 
 1063        elif self.protocol == 'tcp':
 
 1064            set_value('transport', 'transport-tcp', section, pjsip, nmapped,
 
 1066        elif self.protocol == 'tls':
 
 1067            set_value('transport', 'transport-tls', section, pjsip, nmapped,
 
 1070        auth_section = 'auth_reg_' + self.host
 
 1072        if hasattr(self, 'secret') and self.secret:
 
 1073            set_value('password', self.secret, auth_section, pjsip, nmapped,
 
 1075            set_value('username', self.authuser if hasattr(self, 'authuser')
 
 1076                      else self.user, auth_section, pjsip, nmapped, 'auth')
 
 1077            set_value('outbound_auth', auth_section, section, pjsip, nmapped,
 
 1080        client_uri = "sip:%s@" % self.user
 
 1082            client_uri += self.domain
 
 1084            client_uri += self.host
 
 1086        if hasattr(self, 'domainport') and self.domainport:
 
 1087            client_uri += ":" + self.domainport
 
 1089            client_uri += ":" + self.port
 
 1091        set_value('client_uri', client_uri, section, pjsip, nmapped,
 
 1094        server_uri = "sip:%s" % self.host
 
 1096            server_uri += ":" + self.port
 
 1098        set_value('server_uri', server_uri, section, pjsip, nmapped,
 
 1101        if self.outbound_proxy:
 
 1102            set_value('outboundproxy', self.outbound_proxy, section, pjsip,
 
 1103                      nmapped, 'registration')
 
 
 
 1106def map_registrations(sip, pjsip, nmapped):
 
 1108    Gathers all necessary outbound registration data in sip.conf and creates
 
 1109    corresponding registration sections in pjsip.conf
 
 1112        regs = sip.get('general', 'register')
 
 1117        retry_interval = sip.get('general', 'registertimeout')[0]
 
 1119        retry_interval = '20'
 
 1122        max_attempts = sip.get('general', 'registerattempts')[0]
 
 1127        outbound_proxy = sip.get('general', 'outboundproxy')[0]
 
 1132        reg = Registration(i, retry_interval, max_attempts, outbound_proxy)
 
 1133        reg.write(pjsip, nmapped)
 
 
 1136def map_setvars(sip, section, pjsip, nmapped):
 
 1138    Map all setvar in peer section to the appropriate endpoint set_var
 
 1141        setvars = sip.section(section)[0].get('setvar')
 
 1145    for setvar in setvars:
 
 1146        set_value('set_var', setvar, section, pjsip, nmapped)
 
 
 1149def map_peer(sip, section, pjsip, nmapped):
 
 1151    Map the options from a peer section in sip.conf into the appropriate
 
 1152    sections in pjsip.conf
 
 1156            # coming from sip.conf the values should mostly be a list with a
 
 1157            # single value.  In the few cases that they are not a specialized
 
 1158            # function (see merge_value) is used to retrieve the values.
 
 1159            i[1](i[0], sip.get(section, i[0])[0], section, pjsip, nmapped)
 
 1161            pass  # key not found in sip.conf
 
 1163    setup_udptl(section, pjsip, nmapped)
 
 
 1165def find_non_mapped(sections, nmapped):
 
 1167    Determine sip.conf options that were not properly mapped to pjsip.conf
 
 1170    for section, sect in sections.iteritems():
 
 1172            # since we are pulling from sip.conf this should always
 
 1173            # be a single value list
 
 1175            # loop through the section and store any values that were not
 
 1177            for key in sect.keys(True):
 
 1182                    nmapped(section, key, sect[key])
 
 
 1187def map_system(sip, pjsip, nmapped):
 
 1188    section = 'system' # Just a label; you as user can change that
 
 1189    type = 'system' # Not a label, therefore not the same as section
 
 1192        user_agent = sip.get('general', 'useragent')[0]
 
 1193        set_value('user_agent', user_agent, 'global', pjsip, nmapped, 'global')
 
 1199        sipdebug = sip.get('general', 'sipdebug')[0]
 
 1200        set_value('debug', sipdebug, 'global', pjsip, nmapped, 'global')
 
 1205        useroption_parsing = sip.get('general', 'legacy_useroption_parsing')[0]
 
 1206        set_value('ignore_uri_user_options', useroption_parsing, 'global', pjsip, nmapped, 'global')
 
 1211        timer_t1 = sip.get('general', 'timert1')[0]
 
 1212        set_value('timer_t1', timer_t1, section, pjsip, nmapped, type)
 
 1217        timer_b = sip.get('general', 'timerb')[0]
 
 1218        set_value('timer_b', timer_b, section, pjsip, nmapped, type)
 
 1223        compact_headers = sip.get('general', 'compactheaders')[0]
 
 1224        set_value('compact_headers', compact_headers, section, pjsip, nmapped, type)
 
 
 1229def convert(sip, filename, non_mappings, include):
 
 1231    Entry point for configuration file conversion. This
 
 1232    function will create a pjsip.conf object and begin to
 
 1233    map specific sections from sip.conf into it.
 
 1234    Returns the new pjsip.conf object once completed
 
 1236    pjsip = sip.__class__()
 
 1237    non_mappings[filename] = astdicts.MultiOrderedDict()
 
 1238    nmapped = non_mapped(non_mappings[filename])
 
 1240        # Don't duplicate transport and registration configs
 
 1241        map_system(sip, pjsip, nmapped)
 
 1242        map_transports(sip, pjsip, nmapped)
 
 1243        map_registrations(sip, pjsip, nmapped)
 
 1244    map_auth(sip, pjsip, nmapped)
 
 1245    for section in sip.sections():
 
 1246        if section == 'authentication':
 
 1249            map_peer(sip, section, pjsip, nmapped)
 
 1250            map_setvars(sip, section, pjsip, nmapped)
 
 1252    find_non_mapped(sip.defaults(), nmapped)
 
 1253    find_non_mapped(sip.sections(), nmapped)
 
 1255    for key, val in sip.includes().iteritems():
 
 1256        pjsip.add_include(PREFIX + key, convert(val, PREFIX + key,
 
 1257                          non_mappings, True)[0])
 
 1258    return pjsip, non_mappings
 
 
 1261def write_pjsip(filename, pjsip, non_mappings):
 
 1263    Write pjsip.conf file to disk
 
 1266        with open(filename, 'wt') as fp:
 
 1268            fp.write(';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n')
 
 1269            fp.write('Non mapped elements start\n')
 
 1270            fp.write(';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n')
 
 1271            astconfigparser.write_dicts(fp, non_mappings[filename])
 
 1272            fp.write(';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n')
 
 1273            fp.write('Non mapped elements end\n')
 
 1274            fp.write(';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n')
 
 1276            # write out include file(s)
 
 1280        print("Could not open file " + filename + " for writing", file=sys.stderr)
 
 
 1282###############################################################################
 
 1287    Parse command line options and apply them. If invalid input is given,
 
 1288    print usage information
 
 1292    usage = "usage: %prog [options] [input-file [output-file]]\n\n" \
 
 1293        "Converts the chan_sip configuration input-file to the chan_pjsip output-file.\n" \
 
 1294        "The input-file defaults to 'sip.conf'.\n" \
 
 1295        "The output-file defaults to 'pjsip.conf'."
 
 1296    parser = optparse.OptionParser(usage=usage)
 
 1297    parser.add_option('-p', '--prefix', dest='prefix', default=PREFIX,
 
 1298                      help='output prefix for include files')
 
 1299    parser.add_option('-q', '--quiet', dest='quiet', default=False, action='store_true',
 
 1300                      help="don't print messages to stdout")
 
 1302    options, args = parser.parse_args()
 
 1303    PREFIX = options.prefix
 
 1307    sip_filename = args[0] if len(args) else 'sip.conf'
 
 1308    pjsip_filename = args[1] if len(args) == 2 else 'pjsip.conf'
 
 1310    return sip_filename, pjsip_filename
 
 
 1319if __name__ == "__main__":
 
 1320    sip_filename, pjsip_filename = cli_options()
 
 1321    # configuration parser for sip.conf
 
 1322    sip = astconfigparser.MultiOrderedConfigParser()
 
 1323    info('Please, report any issue at:')
 
 1324    info('    https://github.com/asterisk/asterisk/issues/')
 
 1325    info('Reading ' + sip_filename)
 
 1326    sip.read(sip_filename)
 
 1327    info('Converting to PJSIP...')
 
 1328    pjsip, non_mappings = convert(sip, pjsip_filename, dict(), False)
 
 1329    info('Writing ' + pjsip_filename)
 
 1330    write_pjsip(pjsip_filename, pjsip, non_mappings)
 
set_record_on_feature(key, val, section, pjsip, nmapped)
set_tls_private_key(val, pjsip, section, nmapped)
from_encryption_taglen(key, val, section, pjsip, nmapped)
set_transport_common(section, sip, pjsip, protocol, nmapped)
merge_value(key=None, val=None, section=None, pjsip=None, nmapped=None, type='endpoint', section_to=None, key_to=None)
set_tls_cert_file(val, pjsip, section, nmapped)
from_sendrpid(key, val, section, pjsip, nmapped)
ignore(key=None, val=None, section=None, pjsip=None, nmapped=None, type='endpoint')
from_mailbox(key, val, section, pjsip, nmapped)
from_progressinband(key, val, section, pjsip, nmapped)
set_dtmfmode(key, val, section, pjsip, nmapped)
mapping functions - define f(key, val, section) where key/val are the key/value pair to write to give...
set_tls_cipher(val, pjsip, section, nmapped)
section_by_type(section, pjsip, type)
some utility functions
build_host(config, host, section='general', port_key=None)
merge_codec_value(key=None, val=None, section=None, pjsip=None, nmapped=None, type='endpoint', section_to=None, key_to=None)
setup_ident(key, val, section, pjsip, nmapped)
setup_udptl(section, pjsip, nmapped)
from_recordfeature(key, val, section, pjsip, nmapped)
set_media_encryption(key, val, section, pjsip, nmapped)
setup_auth(key, val, section, pjsip, nmapped)
from_host(key, val, section, pjsip, nmapped)
set_value(key=None, val=None, section=None, pjsip=None, nmapped=None, type='endpoint')
from_dtlsenable(key, val, section, pjsip, nmapped)
create_udp(sip, pjsip, nmapped)
from_nat(key, val, section, pjsip, nmapped)
create_tcp(sip, pjsip, nmapped)
set_direct_media(key, val, section, pjsip, nmapped)
get_bind(sip, pjsip, protocol)
set_timers(key, val, section, pjsip, nmapped)
set_record_off_feature(key, val, section, pjsip, nmapped)