# $Id: h225.py 23 2006-11-08 15:45:33Z dugsong $

"""ITU-T H.225.0 Call Signaling."""

from . import dpkt, tpkt
import struct

# H225 Call Signaling
# 
# Call messages and information elements (IEs) are defined by Q.931:
# http://cvsup.de.openbsd.org/historic/comp/doc/standards/itu/Q/Q.931.ps.gz
#
# The User-to-User IEs of H225 are encoded by PER of ASN.1.

# Call Establishment Messages
ALERTING				= 1
CALL_PROCEEDING				= 2
CONNECT					= 7
CONNECT_ACKNOWLEDGE			= 15
PROGRESS				= 3
SETUP					= 5
SETUP_ACKNOWLEDGE			= 13

# Call Information Phase Messages
RESUME					= 38
RESUME_ACKNOWLEDGE			= 46
RESUME_REJECT				= 34
SUSPEND					= 37
SUSPEND_ACKNOWLEDGE			= 45
SUSPEND_REJECT				= 33
USER_INFORMATION			= 32

# Call Clearing Messages
DISCONNECT				= 69
RELEASE					= 77
RELEASE_COMPLETE			= 90
RESTART					= 70
RESTART_ACKNOWLEDGE			= 78

# Miscellaneous Messages
SEGMENT					= 96
CONGESTION_CONTROL			= 121
INFORMATION				= 123
NOTIFY					= 110
STATUS					= 125
STATUS_ENQUIRY				= 117

# Type 1 Single Octet Information Element IDs
RESERVED				= 128
SHIFT					= 144
CONGESTION_LEVEL			= 176
REPEAT_INDICATOR			= 208

# Type 2 Single Octet Information Element IDs
MORE_DATA				= 160
SENDING_COMPLETE			= 161

# Variable Length Information Element IDs 
SEGMENTED_MESSAGE			= 0
BEARER_CAPABILITY			= 4
CAUSE					= 8
CALL_IDENTITY				= 16
CALL_STATE				= 20
CHANNEL_IDENTIFICATION			= 24
PROGRESS_INDICATOR			= 30
NETWORK_SPECIFIC_FACILITIES		= 32
NOTIFICATION_INDICATOR			= 39
DISPLAY					= 40
DATE_TIME				= 41
KEYPAD_FACILITY				= 44
SIGNAL					= 52
INFORMATION_RATE			= 64
END_TO_END_TRANSIT_DELAY		= 66
TRANSIT_DELAY_SELECTION_AND_INDICATION	= 67
PACKET_LAYER_BINARY_PARAMETERS		= 68
PACKET_LAYER_WINDOW_SIZE		= 69
PACKET_SIZE				= 70
CLOSED_USER_GROUP			= 71
REVERSE_CHARGE_INDICATION		= 74
CALLING_PARTY_NUMBER			= 108
CALLING_PARTY_SUBADDRESS		= 109
CALLED_PARTY_NUMBER			= 112
CALLED_PARTY_SUBADDRESS			= 113
REDIRECTING_NUMBER			= 116
TRANSIT_NETWORK_SELECTION		= 120
RESTART_INDICATOR			= 121
LOW_LAYER_COMPATIBILITY			= 124
HIGH_LAYER_COMPATIBILITY		= 125
USER_TO_USER				= 126
ESCAPE_FOR_EXTENSION			= 127

class H225(dpkt.Packet):
    __hdr__ = (
        ('proto', 'B', 8),
        ('ref_len', 'B', 2)
        )

    def unpack(self, buf):
        # TPKT header
        self.tpkt = tpkt.TPKT(buf)
        if self.tpkt.v != 3: 
            raise dpkt.UnpackError('invalid TPKT version')
        if self.tpkt.rsvd != 0:
            raise dpkt.UnpackError('invalid TPKT reserved value')
        n = self.tpkt.len - self.tpkt.__hdr_len__
        if n > len(self.tpkt.data):
            raise dpkt.UnpackError('invalid TPKT length')
        buf = self.tpkt.data

        # Q.931 payload
        dpkt.Packet.unpack(self, buf)
        buf = buf[self.__hdr_len__:]
        self.ref_val = buf[:self.ref_len]
        buf = buf[self.ref_len:]
        self.type = struct.unpack('B', buf[:1])[0]
        buf = buf[1:]

        # Information Elements
        l = []
        while buf:
            ie = self.IE(buf)
            l.append(ie)
            buf = buf[len(ie):]
        self.data = l

    def __len__(self):
        return self.tpkt.__hdr_len__ + \
               self.__hdr_len__ + \
               sum(map(len, self.data))

    def __str__(self):
        return str(self.__bytes__())

    def __bytes__(self):
        return self.tpkt.pack_hdr() + \
               self.pack_hdr() + \
               self.ref_val + \
               struct.pack('B', self.type) + \
               b''.join(map(bytes, self.data))

    class IE(dpkt.Packet):
        __hdr__ = (
            ('type', 'B', 0),
            )

        def unpack(self, buf):
            dpkt.Packet.unpack(self, buf)
            buf = buf[self.__hdr_len__:]

            # single-byte IE
            if self.type & 0x80:
                self.len = 0
                self.data = None
            # multi-byte IE
            else:
                # special PER-encoded UUIE
                if self.type == USER_TO_USER:
                    self.len = struct.unpack('>H', buf[:2])[0]
                    buf = buf[2:]
                # normal TLV-like IE
                else:
                    self.len = struct.unpack('B', buf[:1])[0]
                    buf = buf[1:]
                self.data = buf[:self.len]

        def __len__(self):
            if self.type & 0x80:
                n = 0
            else:
                if self.type == USER_TO_USER:
                    n = 2
                else:
                    n = 1
            return self.__hdr_len__ + \
                   self.len \
                   + n

        def __str__(self):
            return str(self.__bytes__())

        def __bytes__(self):
            if self.type & 0x80:
                length_str = None
            else:
                if self.type == USER_TO_USER:
                    length_str = struct.pack('>H', self.len) 
                else:
                    length_str = struct.pack('B', self.len)
            return struct.pack('B', self.type) + \
                   length_str + \
                   self.data


if __name__ == '__main__':
    import unittest

    class H225TestCase(unittest.TestCase):
        def testPack(self):
            h = H225(self.s)
            self.assertTrue(self.s == bytes(h))

        def testUnpack(self):
            h = H225(self.s)
            self.assertTrue(h.tpkt.v == 3)
            self.assertTrue(h.tpkt.rsvd == 0)
            self.assertTrue(h.tpkt.len == 1041)
            self.assertTrue(h.proto == 8)
            self.assertTrue(h.type == SETUP)
            self.assertTrue(len(h.data) == 3)

            ie = h.data[0]
            self.assertTrue(ie.type == BEARER_CAPABILITY)
            self.assertTrue(ie.len == 3)
            ie = h.data[1]
            self.assertTrue(ie.type == DISPLAY)
            self.assertTrue(ie.len == 14)
            ie = h.data[2]
            self.assertTrue(ie.type == USER_TO_USER)
            self.assertTrue(ie.len == 1008)

        s = b'\x03\x00\x04\x11\x08\x02\x54\x2b\x05\x04\x03\x88\x93\xa5\x28\x0e\x4a\x6f\x6e\x20\x4f\x62\x65\x72\x68\x65\x69\x64\x65\x00\x7e\x03\xf0\x05\x20\xb8\x06\x00\x08\x91\x4a\x00\x04\x01\x40\x0c\x00\x4a\x00\x6f\x00\x6e\x00\x20\x00\x4f\x00\x62\x00\x65\x00\x72\x00\x68\x00\x65\x00\x69\x00\x64\x00\x65\x22\xc0\x09\x00\x00\x3d\x06\x65\x6b\x69\x67\x61\x00\x00\x14\x32\x2e\x30\x2e\x32\x20\x28\x4f\x50\x41\x4c\x20\x76\x32\x2e\x32\x2e\x32\x29\x00\x00\x00\x01\x40\x15\x00\x74\x00\x63\x00\x70\x00\x24\x00\x68\x00\x33\x00\x32\x00\x33\x00\x2e\x00\x76\x00\x6f\x00\x78\x00\x67\x00\x72\x00\x61\x00\x74\x00\x69\x00\x61\x00\x2e\x00\x6f\x00\x72\x00\x67\x00\x42\x87\x23\x2c\x06\xb8\x00\x6a\x8b\x1d\x0c\xb7\x06\xdb\x11\x9e\xca\x00\x10\xa4\x89\x6d\x6a\x00\xc5\x1d\x80\x04\x07\x00\x0a\x00\x01\x7a\x75\x30\x11\x00\x5e\x88\x1d\x0c\xb7\x06\xdb\x11\x9e\xca\x00\x10\xa4\x89\x6d\x6a\x82\x2b\x0e\x30\x40\x00\x00\x06\x04\x01\x00\x4c\x10\x09\x00\x00\x3d\x0f\x53\x70\x65\x65\x78\x20\x62\x73\x34\x20\x57\x69\x64\x65\x36\x80\x11\x1c\x00\x01\x00\x98\xa0\x26\x41\x13\x8a\x00\x98\xa0\x26\x41\x13\x8b\x26\x00\x00\x64\x0c\x10\x09\x00\x00\x3d\x0f\x53\x70\x65\x65\x78\x20\x62\x73\x34\x20\x57\x69\x64\x65\x36\x80\x0b\x0d\x00\x01\x00\x98\xa0\x26\x41\x13\x8b\x00\x2a\x40\x00\x00\x06\x04\x01\x00\x4c\x10\x09\x00\x00\x3d\x09\x69\x4c\x42\x43\x2d\x31\x33\x6b\x33\x80\x11\x1c\x00\x01\x00\x98\xa0\x26\x41\x13\x8a\x00\x98\xa0\x26\x41\x13\x8b\x20\x00\x00\x65\x0c\x10\x09\x00\x00\x3d\x09\x69\x4c\x42\x43\x2d\x31\x33\x6b\x33\x80\x0b\x0d\x00\x01\x00\x98\xa0\x26\x41\x13\x8b\x00\x20\x40\x00\x00\x06\x04\x01\x00\x4e\x0c\x03\x00\x83\x00\x80\x11\x1c\x00\x01\x00\x98\xa0\x26\x41\x13\x8a\x00\x98\xa0\x26\x41\x13\x8b\x16\x00\x00\x66\x0e\x0c\x03\x00\x83\x00\x80\x0b\x0d\x00\x01\x00\x98\xa0\x26\x41\x13\x8b\x00\x4b\x40\x00\x00\x06\x04\x01\x00\x4c\x10\xb5\x00\x53\x4c\x2a\x02\x00\x00\x00\x00\x00\x40\x01\x00\x00\x40\x01\x02\x00\x08\x00\x00\x00\x00\x00\x31\x00\x01\x00\x40\x1f\x00\x00\x59\x06\x00\x00\x41\x00\x00\x00\x02\x00\x40\x01\x00\x00\x80\x11\x1c\x00\x01\x00\x98\xa0\x26\x41\x13\x8a\x00\x98\xa0\x26\x41\x13\x8b\x41\x00\x00\x67\x0c\x10\xb5\x00\x53\x4c\x2a\x02\x00\x00\x00\x00\x00\x40\x01\x00\x00\x40\x01\x02\x00\x08\x00\x00\x00\x00\x00\x31\x00\x01\x00\x40\x1f\x00\x00\x59\x06\x00\x00\x41\x00\x00\x00\x02\x00\x40\x01\x00\x00\x80\x0b\x0d\x00\x01\x00\x98\xa0\x26\x41\x13\x8b\x00\x32\x40\x00\x00\x06\x04\x01\x00\x4c\x10\x09\x00\x00\x3d\x11\x53\x70\x65\x65\x78\x20\x62\x73\x34\x20\x4e\x61\x72\x72\x6f\x77\x33\x80\x11\x1c\x00\x01\x00\x98\xa0\x26\x41\x13\x8a\x00\x98\xa0\x26\x41\x13\x8b\x28\x00\x00\x68\x0c\x10\x09\x00\x00\x3d\x11\x53\x70\x65\x65\x78\x20\x62\x73\x34\x20\x4e\x61\x72\x72\x6f\x77\x33\x80\x0b\x0d\x00\x01\x00\x98\xa0\x26\x41\x13\x8b\x00\x1d\x40\x00\x00\x06\x04\x01\x00\x4c\x60\x1d\x80\x11\x1c\x00\x01\x00\x98\xa0\x26\x41\x13\x8a\x00\x98\xa0\x26\x41\x13\x8b\x13\x00\x00\x69\x0c\x60\x1d\x80\x0b\x0d\x00\x01\x00\x98\xa0\x26\x41\x13\x8b\x00\x1d\x40\x00\x00\x06\x04\x01\x00\x4c\x20\x1d\x80\x11\x1c\x00\x01\x00\x98\xa0\x26\x41\x13\x8a\x00\x98\xa0\x26\x41\x13\x8b\x13\x00\x00\x6a\x0c\x20\x1d\x80\x0b\x0d\x00\x01\x00\x98\xa0\x26\x41\x13\x8b\x00\x01\x00\x01\x00\x01\x00\x01\x00\x81\x03\x02\x80\xf8\x02\x70\x01\x06\x00\x08\x81\x75\x00\x0b\x80\x13\x80\x01\xf4\x00\x01\x00\x00\x01\x00\x00\x01\x00\x00\x0c\xc0\x01\x00\x01\x80\x0b\x80\x00\x00\x20\x20\x09\x00\x00\x3d\x0f\x53\x70\x65\x65\x78\x20\x62\x73\x34\x20\x57\x69\x64\x65\x36\x80\x00\x01\x20\x20\x09\x00\x00\x3d\x09\x69\x4c\x42\x43\x2d\x31\x33\x6b\x33\x80\x00\x02\x24\x18\x03\x00\xe6\x00\x80\x00\x03\x20\x20\xb5\x00\x53\x4c\x2a\x02\x00\x00\x00\x00\x00\x40\x01\x00\x00\x40\x01\x02\x00\x08\x00\x00\x00\x00\x00\x31\x00\x01\x00\x40\x1f\x00\x00\x59\x06\x00\x00\x41\x00\x00\x00\x02\x00\x40\x01\x00\x00\x80\x00\x04\x20\x20\x09\x00\x00\x3d\x11\x53\x70\x65\x65\x78\x20\x62\x73\x34\x20\x4e\x61\x72\x72\x6f\x77\x33\x80\x00\x05\x20\xc0\xef\x80\x00\x06\x20\x40\xef\x80\x00\x07\x08\xe0\x03\x51\x00\x80\x01\x00\x80\x00\x08\x08\xd0\x03\x51\x00\x80\x01\x00\x80\x00\x09\x83\x01\x50\x80\x00\x0a\x83\x01\x10\x80\x00\x0b\x83\x01\x40\x00\x80\x01\x03\x06\x00\x00\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x01\x00\x07\x00\x08\x00\x00\x09\x01\x00\x0a\x00\x0b\x07\x01\x00\x32\x80\xa6\xff\x4c\x02\x80\x01\x80'

    unittest.main()
