class SipGenericHF(object):
    hf_names = None	# Set this in each subclass!!
    body = None
    parsed = False

    def __init__(self, body, name = None):
        self.body = body
        if name != None:
            self.hf_names = (name.lower(),)

    def parse(self):
        pass

    def localStr(self, local_addr = None, local_port = None):
        return self.__str__()

    def __str__(self):
        return self.body

    def getCopy(self):
        return self.__class__(self.body)

    def getCanName(self, name, compact = False):
        return name.capitalize() class SipCSeq(SipGenericHF):
    hf_names = ('cseq',)
    cseq = None
    method = None

    def __init__(self, body = None, cseq = None, method = None):
        SipGenericHF.__init__(self, body)
        if body == None:
            self.parsed = True
            self.method = method
            if cseq != None:
                self.cseq = cseq
            else:
                self.cseq = 1

    def parse(self):
        cseq, self.method = self.body.split()
        self.cseq = int(cseq)
        self.parsed = True

    def __str__(self):
        if not self.parsed:
            return self.body
        return str(self.cseq) + ' ' + self.method

    def getCSeq(self):
        return (self.cseq, self.method)

    def getCSeqNum(self):
        return self.cseq

    def getCSeqMethod(self):
        return self.method

    def getCopy(self):
        if not self.parsed:
            return SipCSeq(self.body)
        return SipCSeq(cseq = self.cseq, method = self.method)

    def getCanName(self, name, compact = False):
        return 'CSeq'

    def incCSeqNum(self):
        self.cseq += 1
        return self.cseq class SipCallId(SipGenericHF):
    hf_names = ('call-id', 'i')
    body = None

    def __init__(self, body = None):
        SipGenericHF.__init__(self, body)
        self.parsed = True
        if body == None:
            salt = str((random() * 1000000000) + time())
            self.body = md5(salt.encode()).hexdigest() + '@' + str(SipConf.my_address)

    def __add__(self, other):
        return SipCallId(self.body + str(other))

    def genCallId(self):
        salt = str((random() * 1000000000) + time())
        self.body = md5(salt.encode()).hexdigest() + '@' + str(SipConf.my_address)

    def getCanName(self, name, compact = False):
        if compact:
            return 'i'
        return 'Call-ID' class SipFrom(SipAddressHF):
    hf_names = ('from', 'f')
    relaxedparser = True

    def __init__(self, body = None, address = None):
        SipAddressHF.__init__(self, body, address)
        if body == None and address == None:
            self.address = SipAddress(name = 'Anonymous', url = SipURL(host = SipConf.my_address, port = SipConf.my_port))

    def getTag(self):
        return self.address.getParam('tag')

    def genTag(self):
        salt = str((random() * 1000000000) + time())
        self.address.setParam('tag', md5(salt.encode()).hexdigest())

    def setTag(self, value):
        self.address.setParam('tag', value)

    def delTag(self):
        self.address.delParam('tag')

    def getCanName(self, name, compact = False):
        if compact:
            return 'f'
        return 'From' class SipTo(SipFrom):
    hf_names = ('to', 't')
    relaxedparser = True

    def getCanName(self, name, compact = False):
        if compact:
            return 't'
        return 'To' class SipMaxForwards(SipNumericHF):
    hf_names = ('max-forwards',)

    def __init__(self, body = None, number = 70):
        SipNumericHF.__init__(self, body, number)

    def getCanName(self, name, compact = False):
        return 'Max-Forwards' class SipVia(SipGenericHF):
    hf_names = ('via', 'v')

    sipver = None
    hostname = None
    port = None
    params = None

    def __init__(self, body = None, sipver = None, hostname = None, port = None, params = None):
        if body != None and body.find(',') > -1:
            raise ESipHeaderCSV(None, body.split(','))
        SipGenericHF.__init__(self, body)
        if body == None:
            self.parsed = True
            self.params = {}
            if sipver == None:
                self.sipver = 'SIP/2.0/UDP'
            else:
                self.sipver = sipver
            if hostname == None:
                self.hostname = SipConf.my_address
                self.port = SipConf.my_port
                self.params['rport'] = None
            else:
                self.hostname = hostname
                self.port = port
            if params != None:
                self.params = params

    def parse(self):
        self.params = {}
        self.sipver, hostname = self.body.split(None, 1)
        hcomps = [x.strip() for x in hostname.split(';')]
        for param in hcomps[1:]:
            sparam = param.split('=', 1)
            if len(sparam) == 1:
                val = None
            else:
                val = sparam[1]
            self.params[sparam[0]] = val
        if hcomps[0].startswith('['):
            hcomps = hcomps[0].split(']', 1)
            self.hostname = hcomps[0] + ']'
            hcomps = hcomps[1].split(':', 1)
        else:
            hcomps = hcomps[0].split(':', 1)
            self.hostname = hcomps[0]
        if len(hcomps) == 2:
            try:
                self.port = int(hcomps[1])
            except Exception as e:
                # XXX: some bad-ass devices send us port number twice
                # While not allowed by the RFC, deal with it
                portparts = hcomps[1].split(':', 1)
                if len(portparts) != 2 or portparts[0] != portparts[1]:
                    raise e
                self.port = int(portparts[0])
        else:
            self.port = None
        self.parsed = True

    def __str__(self):
        return self.localStr()

    def localStr(self, local_addr = None, local_port = None):
        if not self.parsed:
            return self.body
        if local_addr != None and 'my' in dir(self.hostname):
            s = self.sipver + ' ' + local_addr
        else:
            s = self.sipver + ' ' + str(self.hostname)
        if self.port != None:
            if local_port != None and 'my' in dir(self.port):
                s += ':' + str(local_port)
            else:
                s += ':' + str(self.port)
        for key, val in self.params.items():
            s += ';' + key
            if val != None:
                s += '=' + val
        return s

    def getCopy(self):
        if not self.parsed:
            return SipVia(self.body)
        return SipVia(sipver = self.sipver, hostname = self.hostname, port = self.port, params = self.params.copy())

    def genBranch(self):
        salt = str((random() * 1000000000) + time())
        self.params['branch'] = 'z9hG4bK' + md5(salt.encode()).hexdigest()

    def getBranch(self):
        return self.params.get('branch', None)

    def setParam(self, name, value = None):
        self.params[name] = value

    def getAddr(self):
        if self.port == '':
            return (self.hostname, SipConf.default_port)
        else:
            return (self.hostname, self.port)

    def getTAddr(self):
        rport = self.params.get('rport', None)
        if rport != None:
            rport = int(rport)
            if rport <= 0:
                rport = None
        if rport == None:
            rport = self.getAddr()[1]
            if rport == None:
                rport = SipConf.default_port
        return (self.params.get('received', self.getAddr()[0]), rport)

    def getCanName(self, name, compact = False):
        if compact:
            return 'v'
        return 'Via' class SipContentLength(SipNumericHF):
    hf_names = ('content-length', 'l')

    def getCanName(self, name, compact = False):
        if compact:
            return 'l'
        return 'Content-Length' class SipContentType(SipGenericHF):
    hf_names = ('content-type', 'c')

    def __init__(self, body):
        SipGenericHF.__init__(self, body)
        self.parsed = True

    def getCanName(self, name, compact = False):
        if compact:
            return 'c'
        return 'Content-Type' class SipExpires(SipNumericHF):
    hf_names = ('expires',)

    def __init__(self, body = None, number = 300):
        SipNumericHF.__init__(self, body, number) class SipRecordRoute(SipFrom):
    hf_names = ('record-route',)
    relaxedparser = False

    def getCanName(self, name, compact = False):
        if name == 'record-route':
            return 'Record-Route'
        else:
            return 'Route'

    def getAddr(self):
        return self.address.url.getAddr() class SipRoute(SipFrom):
    hf_names = ('route',)
    relaxedparser = False

    def getCanName(self, name, compact = False):
        if name == 'record-route':
            return 'Record-Route'
        else:
            return 'Route'

    def getAddr(self):
        return self.address.url.getAddr() class SipContact(SipAddressHF):
    hf_names = ('contact', 'm')
    asterisk = False

    def __init__(self, body = None, address = None):
        if body == '*':
            SipGenericHF.__init__(self, body)
            self.asterisk = True
            return
        SipAddressHF.__init__(self, body, address)
        if body == None and address == None:
            self.address = SipAddress(name = 'Anonymous', url = SipURL(host = SipConf.my_address, port = SipConf.my_port))

    def getCanName(self, name, compact = False):
        if compact:
            return 'm'
        return 'Contact'

    def parse(self):
        if not self.asterisk:
            return SipAddressHF.parse(self) class SipWWWAuthenticate(SipGenericHF):
    hf_names = ('www-authenticate',)
    aclass = SipAuthorization
    realm = None
    nonce = None
    qop = None
    algorithm = None
    opaque = None
    otherparams = None
    ho = HashOracle()
    rng = Random.new()
    try:
        rng.read(1).hex()
        readhex = lambda self, x: self.rng.read(x).hex()
    except AttributeError:
        # Python 2.7 shim
        readhex = lambda self, x: self.rng.read(x).encode('hex')

    def __init__(self, body = None, realm = None, nonce = None, \
      algorithm = None):
        self.otherparams = []
        SipGenericHF.__init__(self, body)
        if body != None:
            return
        self.parsed = True
        if algorithm != None:
            self.algorithm = algorithm
            self.qop = ('auth',)
        if nonce == None:
            nonce = self.ho.emit_challenge(NameList2AlgMask((self.algorithm,)))
        if realm == None:
            realm = SipConf.my_address
        self.realm = realm
        self.nonce = nonce

    def parse(self):
        parts = self.body.split(' ', 1)[1].strip().split('"')
        if len(parts) % 2 != 0 and len(parts[-1]) == 0:
            parts.pop()
        while len(parts) > 0:
            parts1 = [x.strip().split('=', 1) for x in parts.pop(0).strip(' ,=').split(',')]
            if len(parts) > 0:
                parts1[-1].append(parts.pop(0))
            for name, value in parts1:
                if name == 'realm':
                    self.realm = value
                elif name == 'nonce':
                    self.nonce = value
                elif name == 'algorithm':
                    if value == 'md5':
                        value = 'MD5'
                    self.algorithm = value
                elif name == 'qop':
                    self.qop = [x.strip() for x in value.split(',')]
                elif name == 'opaque':
                    self.opaque = value
                else:
                    self.otherparams.append((name, value))
        self.parsed = True

    def __str__(self):
        return self.localStr()

    def localStr(self, local_addr = None, local_port = None):
        if not self.parsed:
            return self.body
        if local_addr == None or 'my' not in dir(self.realm):
            local_addr = self.realm
        rval = 'Digest realm="%s",nonce="%s"' % (local_addr, self.nonce)
        if self.qop != None:
            sqop = self.qop[0]
            for qop in self.qop[1:]:
                sqop += ',%s' % qop
            if len(self.qop) > 1:
                rval += ',qop="%s"' % (sqop,)
            else:
                rval += ',qop=%s' % (sqop,)
        if self.algorithm != None:
            rval += ',algorithm=%s' % (self.algorithm,)
        if self.opaque != None:
            rval += ',opaque="%s"' % (self.opaque,)
        for param in self.otherparams:
            rval += ',%s="%s"' % param
        return rval

    def getCopy(self):
        if not self.parsed:
            return self.__class__(self.body)
        cself = self.__class__(realm = self.realm, nonce = self.nonce)
        cself.algorithm = self.algorithm
        cself.qop = self.qop
        cself.opaque = self.opaque
        if len(self.otherparams) > 0:
            cself.otherparams = self.otherparams[:]
        return cself

    def getCanName(self, name, compact = False):
        return 'WWW-Authenticate'

    def getRealm(self):
        return self.realm

    def getNonce(self):
        return self.nonce

    def genAuthHF(self, username, password, method, uri, body = None, qop = None):
        auth = self.aclass(realm = self.realm, nonce = self.nonce, uri = uri, username = username)
        auth.algorithm = self.algorithm
        if self.qop is not None and qop is not None:
            auth.qop = qop
            auth.nc = '00000001'
            auth.cnonce = self.readhex(4)
        if self.opaque != None:
            auth.opaque = self.opaque
        auth.genAuthResponse(password, method, body)
        return auth

    def supportedAlgorithm(self):
        if self.qop is not None:
            qops = [x for x in self.qop if x in ('auth', 'auth-int')]
            if len(qops) == 0:
                return False
            qop = qops[0]
        elif self.algorithm is not None and (self.algorithm.endswith('-sess') or self.algorithm != 'MD5'):
            # -sess variants and RFC8760 algorithms mandate qop
            return False
        else:
            qop = None
        return (IsDigestAlgSupported(self.algorithm), qop) class SipAuthorization(SipGenericHF):
    hf_names = ('authorization',)
    username = None
    uri = None
    realm = None
    nonce = None
    response = None
    qop = None
    cnonce = None
    nc = None
    algorithm = None
    otherparams = None
    ho = HashOracle()

    def __init__(self, body = None, username = None, uri = None, realm = None, nonce = None, response = None, \
                 cself = None):
        SipGenericHF.__init__(self, body)
        if body != None:
            return
        self.parsed = True
        if cself != None:
            self.username = cself.username
            self.uri = cself.uri
            self.realm = cself.realm
            self.nonce = cself.nonce
            self.response = cself.response
            self.qop = cself.qop
            self.cnonce = cself.cnonce
            self.nc = cself.nc
            self.algorithm = cself.algorithm
            self.otherparams = cself.otherparams[:]
            return
        self.username = username
        self.uri = uri
        self.realm = realm
        self.nonce = nonce
        self.response = response
        self.otherparams = []

    def parse(self):
        self.otherparams = []
        for name, value in [x.strip(', ').split('=', 1) for x in self.body.split(' ', 1)[1].split(',')]:
            ci_name = name.lower()
            if ci_name == 'username':
                self.username = value.strip('"')
            elif ci_name == 'uri':
                self.uri = value.strip('"')
            elif ci_name == 'realm':
                self.realm = value.strip('"')
            elif ci_name == 'nonce':
                self.nonce = value.strip('"')
            elif ci_name == 'response':
                self.response = value.strip('"')
            elif ci_name == 'qop':
                self.qop = value.strip('"')
            elif ci_name == 'cnonce':
                self.cnonce = value.strip('"')
            elif ci_name == 'nc':
                self.nc = value.strip('"')
            elif ci_name == 'algorithm':
                self.algorithm = value.strip('"')
            else:
                self.otherparams.append((name, value))
        self.parsed = True

    def genAuthResponse(self, password, method, body):
        HA1 = DigestCalcHA1(self.algorithm, self.username, self.realm, password, \
          self.nonce, self.cnonce)
        self.response = DigestCalcResponse(self.algorithm, HA1, self.nonce, \
          self.nc, self.cnonce, self.qop, method, self.uri, body)

    def __str__(self):
        if not self.parsed:
            return self.body
        rval = 'Digest username="%s",realm="%s",nonce="%s",uri="%s",response="%s"' % \
               (self.username, self.realm, self.nonce, self.uri, self.response)
        if self.algorithm != None:
            rval += ',algorithm=%s' % (self.algorithm,)
        if self.qop != None:
            rval += ',qop=%s,nc=%s,cnonce="%s"' % (self.qop, self.nc, self.cnonce)
        for param in self.otherparams:
            rval += ',%s=%s' % param
        return rval

    def getCopy(self):
        if not self.parsed:
            return self.__class__(self.body)
        return self.__class__(cself = self)

    def verify(self, password, method, body = None):
        if not self.parsed:
            self.parse()
        HA1 = DigestCalcHA1(self.algorithm, self.username, self.realm, password, self.nonce, self.cnonce)
        return self.verifyHA1(HA1, method, body)

    def verifyHA1(self, HA1, method, body):
        if not self.parsed:
            self.parse()
        if self.algorithm not in _HASH_FUNC:
            return False
        if self.qop != None and self.qop not in ('auth', 'auth-int'):
            return False
        algmask = _HASH_FUNC[self.algorithm][1]
        if not self.ho.validate_challenge(self.nonce, (algmask,)):
            return False
        response = DigestCalcResponse(self.algorithm, HA1, self.nonce, self.nc, \
          self.cnonce, self.qop, method, self.uri, body)
        return response == self.response

    def getCanName(self, name, compact = False):
        return 'Authorization' class SipServer(SipGenericHF):
    hf_names = ('server',)
    name = None

    def __init__(self, body = None, name = None):
        SipGenericHF.__init__(self, body)
        self.parsed = True
        if body != None:
            self.name = body
        elif name != None:
            self.name = name
        else:
            self.name = SipConf.my_uaname

    def __str__(self):
        return self.name

    def getCopy(self):
        return self.__class__(name = self.name) class SipUserAgent(SipServer):
    hf_names = ('user-agent',)

    def getCanName(self, name, compact = False):
        return 'User-Agent' class SipCiscoGUID(SipGenericHF):
    hf_names = ('cisco-guid', 'h323-conf-id')
    ciscoGUID = None

    def __init__(self, body = None, ciscoGUID = None):
        SipGenericHF.__init__(self, body)
        if body != None:
            return
        self.parsed = True
        if ciscoGUID != None:
            self.ciscoGUID = ciscoGUID
        else:
            salt = str((random() * 1000000000) + time())
            s = md5(salt.encode()).hexdigest()
            self.ciscoGUID = (int(s[0:8], 16), int(s[8:16], 16), int(s[16:24], 16), int(s[24:32], 16))

    def parse(self):
        self.ciscoGUID = tuple([int(x) for x in  self.body.split('-', 3)])
        self.parsed = True

    def __str__(self):
        if not self.parsed:
            return self.body
        return '%d-%d-%d-%d' % self.ciscoGUID

    def getCiscoGUID(self):
        return self.ciscoGUID

    def hexForm(self):
        return '%.8X %.8X %.8X %.8X' % self.ciscoGUID

    def getCanName(self, name, compact = False):
        if name.lower() == 'h323-conf-id':
            return 'h323-conf-id'
        else:
            return 'cisco-GUID'

    def getCopy(self):
        if not self.parsed:
            return SipCiscoGUID(self.body)
        return SipCiscoGUID(ciscoGUID = self.ciscoGUID) class SipAlso(SipAddressHF):
    hf_names = ('also',) class SipReferTo(SipAddressHF):
    hf_names = ('refer-to', 'r') class SipCCDiversion(SipAddressHF):
    hf_names = ('cc-diversion',)

    def getCanName(self, name, compact = False):
        return 'CC-Diversion' class SipReferredBy(SipAddressHF):
    hf_names = ('referred-by',) class SipProxyAuthenticate(SipWWWAuthenticate):
    hf_names = ('proxy-authenticate',)
    aclass = SipProxyAuthorization

    def getCanName(self, name, compact = False):
        return 'Proxy-Authenticate' class SipProxyAuthorization(SipAuthorization):
    hf_names = ('proxy-authorization',)

    def getCanName(self, name, compact = False):
        return 'Proxy-Authorization' class SipReplaces(SipGenericHF):
    hf_names = ('replaces',)
    call_id = None
    from_tag = None
    to_tag = None
    early_only = False
    params = None

    def __init__(self, body = None, call_id = None, from_tag = None, to_tag = None, \
      early_only = False, params = None):
        SipGenericHF.__init__(self, body)
        if body != None:
            return
        self.parsed = True
        self.params = []
        self.call_id = call_id
        self.from_tag = from_tag
        self.to_tag = to_tag
        self.early_only = early_only
        if params != None:
            self.params = params[:]

    def parse(self):
        self.params = []
        params = self.body.split(';')
        self.call_id = params.pop(0)
        for param in params:
            if param.startswith('from-tag='):
                self.from_tag = param[len('from-tag='):]
            elif param.startswith('to-tag='):
                self.to_tag = param[len('to-tag='):]
            elif param == 'early-only':
                self.early_only = True
            else:
                self.params.append(param)
        self.parsed = True

    def __str__(self):
        if not self.parsed:
            return self.body
        res = '%s;from-tag=%s;to-tag=%s' % (self.call_id, self.from_tag, self.to_tag)
        if self.early_only:
            res += ';early-only'
        for param in self.params:
            res += ';' + param
        return res

    def getCopy(self):
        if not self.parsed:
            return SipReplaces(self.body)
        return SipReplaces(call_id = self.call_id, from_tag = self.from_tag, to_tag = self.to_tag, \
          early_only = self.early_only, params = self.params) class SipPAssertedIdentity(SipFrom):
    hf_names = ('p-asserted-identity',)

    def getCanName(self, name, compact = False):
        return 'P-Asserted-Identity'

    def getAddr(self):
        return self.address.url.getAddr() class SipReason(SipGenericHF):
    '''
    Class that implements RFC 3326 Reason header field.
    '''
    hf_names = ('reason',)
    protocol = None
    cause = None
    reason = None

    def __init__(self, body = None, protocol = None, cause = None, reason = None):
        SipGenericHF.__init__(self, body)
        if body == None:
            self.parsed = True
            self.protocol = protocol
            self.cause = cause
            self.reason = reason

    def parse(self):
        protocol, reason_params = self.body.split(';', 1)
        self.protocol = protocol.strip()
        for reason_param in reason_params.split(';'):
            rp_name, rp_value = [x.strip() for x in reason_param.split('=', 1)]
            if rp_name == 'cause':
                self.cause = int(rp_value)
            elif rp_name == 'text':
                self.reason = rp_value.strip('"')
        assert(self.cause != None)
        self.parsed = True

    def __str__(self):
        if not self.parsed:
            return self.body
        if self.reason == None:
            return '%s; cause=%d' % (self.protocol, self.cause)
        return '%s; cause=%d; text="%s"' % (self.protocol, self.cause, self.reason)

    def getCopy(self):
        if not self.parsed:
            return SipReason(self.body)
        return SipReason(protocol = self.protocol, cause = self.cause, reason = self.reason) class SipAllow(SipGenericHF):
    hf_names = ('allow',)
    methods = None

    def __init__(self, body = None, methods = None):
        SipGenericHF.__init__(self, body)
        if body == None:
            self.parsed = True
            self.methods = methods[:]

    def parse(self):
        self.methods = [x.strip() for x in self.body.split(',')]
        self.parsed = True

    def __str__(self):
        if not self.parsed:
            return self.body
        return reduce(lambda x, y: '%s, %s' % (x, y), self.methods)

    def getCopy(self):
        if not self.parsed:
            return SipAllow(self.body)
        return SipAllow(methods = self.methods)

    def getCanName(self, name, compact = False):
        return 'Allow' class SipSupported(SipGenericHF):
    hf_names = ('supported',)
    caps = None

    def __init__(self, body = None, caps = None):
        SipGenericHF.__init__(self, body)
        if body == None:
            self.parsed = True
            self.caps = caps[:]

    def parse(self):
        self.caps = [x.strip() for x in self.body.split(',')]
        self.parsed = True

    def __str__(self):
        if not self.parsed:
            return self.body
        return reduce(lambda x,y: '%s,%s' % (x, y), self.caps)

    def getCopy(self):
        if not self.parsed:
            return SipSupported(self.body)
        return SipSupported(caps = self.caps)

    def getCanName(self, name, compact = False):
        if compact:
            return 'k'
        return 'Supported' class ESipHeaderCSV(Exception):
    def __init__(self, name, bodys):
        Exception.__init__(self)
        self.name = name
        self.bodys = bodys class SipRSeq(SipNumericHF):
    hf_names = ('rseq',)

    def __init__(self, body = None, number = 1):
        SipNumericHF.__init__(self, body, number)

    def getCanName(self, name, compact = False):
        return 'RSeq' class SipRAck(SipCSeq):
    hf_names = ('rack',)
    rseq = None

    def __init__(self, body = None, rseq = None, cseq = None, method = None):
        if body == None:
            self.rseq = rseq
            SipCSeq.__init__(self, cseq = cseq, method = method)
            return
        SipCSeq.__init__(self, body)

    def parse(self):
        rseq, cseq, self.method = self.body.split(None, 2)
        self.rseq = int(rseq)
        self.cseq = int(cseq)
        self.parsed = True

    def getCopy(self):
        if not self.parsed:
            return SipRAck(self.body)
        return SipRAck(rseq = self.rseq, cseq = self.cseq, method = self.method)

    def getCanName(self, name, compact = False):
        return 'RAck'

    def getRSeq(self):
        cseq, method = SipCSeq.getCSeq(self)
        return (self.rseq, cseq, method)

    def __str__(self):
        if not self.parsed:
            return self.body
        return '%d %d %s' % (self.rseq, self.cseq, self.method) class SipWarning(SipGenericHF):
    hf_names = ('warning',)
    code = 399
    agent = socket.gethostname()
    text = None

    def __init__(self, body = None, cself = None, code = None, text = None):
        SipGenericHF.__init__(self, body)
        if body != None:
            return
        self.parsed = True
        if cself != None:
            self.code, self.agent, self.text = \
              cself.code, cself.agent, cself.text
        else:
            self.agent = socket.gethostname()
            if code != None:
                self.code = code
            self.text = text.replace('"', "'")

    def parse(self):
        code, self.agent, text = self.body.split(None, 2)
        self.text = text.strip('"')
        self.code = int(code)
        self.parsed = True

    def __str__(self):
        if not self.parsed:
            return self.body
        return '%d %s "%s"' % (self.code, self.agent, self.text)

    def getCopy(self):
        return self.__class__(cself = self) class SipDiversion(SipAddressHF):
    hf_names = ('diversion',)

    def getCanName(self, name, compact = False):
        return 'Diversion'
from sippy.SipGenericHF import SipGenericHF
from sippy.SipCSeq import SipCSeq
from sippy.SipCallId import SipCallId
from sippy.SipFrom import SipFrom
from sippy.SipTo import SipTo
from sippy.SipMaxForwards import SipMaxForwards
from sippy.SipVia import SipVia
from sippy.SipContentLength import SipContentLength
from sippy.SipContentType import SipContentType
from sippy.SipExpires import SipExpires
from sippy.SipRecordRoute import SipRecordRoute
from sippy.SipRoute import SipRoute
from sippy.SipContact import SipContact
from sippy.SipWWWAuthenticate import SipWWWAuthenticate
from sippy.SipAuthorization import SipAuthorization
from sippy.SipServer import SipServer
from sippy.SipUserAgent import SipUserAgent
from sippy.SipCiscoGUID import SipCiscoGUID
from sippy.SipAlso import SipAlso
from sippy.SipReferTo import SipReferTo
from sippy.SipCCDiversion import SipCCDiversion
from sippy.SipReferredBy import SipReferredBy
from sippy.SipProxyAuthenticate import SipProxyAuthenticate
from sippy.SipProxyAuthorization import SipProxyAuthorization
from sippy.SipReplaces import SipReplaces
from sippy.SipPAssertedIdentity import SipPAssertedIdentity
from sippy.SipReason import SipReason
from sippy.SipAllow import SipAllow
from sippy.SipSupported import SipSupported
from sippy.ESipHeaderCSV import ESipHeaderCSV
from sippy.SipRSeq import SipRSeq
from sippy.SipRAck import SipRAck
from sippy.SipWarning import SipWarning
from sippy.SipDiversion import SipDiversion
# Copyright (c) 2003-2005 Maxim Sobolev. All rights reserved.
# Copyright (c) 2006-2014 Sippy Software, Inc. All rights reserved.
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation and/or
# other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


_hf_types = (SipCSeq, SipCallId, SipFrom, SipTo, SipMaxForwards, SipVia, SipContentLength, \
             SipContentType, SipExpires, SipRecordRoute, SipRoute, SipContact, SipWWWAuthenticate, \
             SipAuthorization, SipServer, SipUserAgent, SipCiscoGUID, SipAlso, SipReferTo, \
             SipCCDiversion, SipReferredBy, SipProxyAuthenticate, SipProxyAuthorization, \

             SipReplaces, SipPAssertedIdentity, SipReason, SipAllow, SipSupported, SipRSeq, \