[BACK]Return to mumble_protocol.py CVS log [TXT][DIR] Up to [contributed] / MumbleDicebot

Annotation of MumbleDicebot/mumble_protocol.py, Revision 1.1

1.1     ! rubenllo    1: from twisted.internet import protocol, task
        !             2: from utils import parse_varint
        !             3: import mumble_protobuf
        !             4: import struct
        !             5:
        !             6: MUMBLE_VERSION = 66052  # 1.2.4
        !             7: LOGGING = True
        !             8:
        !             9:
        !            10: # Packet types
        !            11: class Packet:
        !            12:     VERSION      = 0
        !            13:     UDPTUNNEL    = 1
        !            14:     AUTHENTICATE = 2
        !            15:     PING         = 3
        !            16:     USERSTATE    = 9
        !            17:     TEXTMESSAGE  = 11
        !            18:
        !            19: PACKET_NAMES = {
        !            20:     0: "Version",
        !            21:     1: "UDPTunnel",
        !            22:     2: "Authenticate",
        !            23:     3: "Ping",
        !            24:     4: "Reject",
        !            25:     5: "ServerSync",
        !            26:     6: "ChannelRemove",
        !            27:     7: "ChannelState",
        !            28:     8: "UserRemove",
        !            29:     9: "UserState",
        !            30:     10: "BanList",
        !            31:     11: "TextMessage",
        !            32:     12: "PermissionDenied",
        !            33:     13: "ACL",
        !            34:     14: "QueryUsers",
        !            35:     15: "CryptSetup",
        !            36:     16: "ContextActionModify",
        !            37:     17: "ContextAction",
        !            38:     18: "UserList",
        !            39:     19: "VoiceTarget",
        !            40:     20: "PermissionQuery",
        !            41:     21: "CodecVersion",
        !            42:     22: "UserStats",
        !            43:     23: "RequestBlob",
        !            44:     24: "ServerConfig",
        !            45:     25: "SuggestConfig"
        !            46: }
        !            47:
        !            48:
        !            49: class VoicePacket():
        !            50:     def __init__(self):
        !            51:         self.session = 0
        !            52:         self.type = 0
        !            53:         self.target = 0
        !            54:         self.sequence = 0
        !            55:         self.lengths = []
        !            56:         self.frames = []
        !            57:
        !            58:     def __str__(self):
        !            59:         s = "Session: {}\nType: {}\nTarget: {}\nSequence: {}\n"
        !            60:         return s.format(self.session, self.type, self.target, self.sequence)
        !            61:
        !            62:
        !            63: class MumbleClient(protocol.Protocol):
        !            64:     """Implements mumble's protocol for communicating with a murmur server.
        !            65:     http://mumble.sourceforge.net/Protocol"""
        !            66:
        !            67:     def connectionMade(self):
        !            68:         # Send version packet
        !            69:         self.send_version()
        !            70:
        !            71:         # Sends authentication packet
        !            72:         self.send_auth()
        !            73:
        !            74:         # Starts sending heartbeat
        !            75:         self.heartbeat = task.LoopingCall(self.send_ping)
        !            76:         self.heartbeat.start(10, now=False)
        !            77:
        !            78:     def dataReceived(self, data):
        !            79:         while data:
        !            80:             p_type, parsed, data = self.unpack_data(data)
        !            81:
        !            82:             if LOGGING and p_type not in [1, 3, 7]:
        !            83:                 print "Type:", parsed.DESCRIPTOR.name
        !            84:                 print parsed
        !            85:
        !            86:             if p_type in self.get_handlers().keys():
        !            87:                 self.get_handlers()[p_type](parsed)
        !            88:
        !            89:     def connectionLost(self, reason):
        !            90:         print "Connection lost"
        !            91:
        !            92:     # Generates the mumble protocol packets
        !            93:     def pack_data(self, packet_type, payload):
        !            94:         return struct.pack(">hi%ds" % len(payload), packet_type, len(payload), payload)
        !            95:
        !            96:     def send_version(self):
        !            97:         client_version = mumble_protobuf.Version()
        !            98:         client_version.version = MUMBLE_VERSION
        !            99:         payload = client_version.SerializeToString()
        !           100:         packet = self.pack_data(Packet.VERSION, payload)
        !           101:         self.transport.write(packet)
        !           102:
        !           103:     def send_auth(self):
        !           104:         client_auth = mumble_protobuf.Authenticate()
        !           105:         client_auth.username = self.factory.nickname
        !           106:         client_auth.password = self.factory.password
        !           107:         client_auth.celt_versions.append(-2147483637)
        !           108:         client_auth.celt_versions.append(-2147483632)
        !           109:         client_auth.opus = True
        !           110:         payload = client_auth.SerializeToString()
        !           111:         packet = self.pack_data(Packet.AUTHENTICATE, payload)
        !           112:         self.transport.write(packet)
        !           113:
        !           114:     def send_ping(self):
        !           115:         ping = mumble_protobuf.Ping()
        !           116:         payload = ping.SerializeToString()
        !           117:         packet = self.pack_data(Packet.PING, payload)
        !           118:         self.transport.write(packet)
        !           119:
        !           120:     def send_textmessage(self, text, channels=[], users=[]):
        !           121:         """Send chat message to a list of channels or users by ids"""
        !           122:         msg = mumble_protobuf.TextMessage()
        !           123:         msg.message = text
        !           124:         if channels:
        !           125:             msg.channel_id.extend(channels)
        !           126:         if users:
        !           127:             msg.session.extend(users)
        !           128:         payload = msg.SerializeToString()
        !           129:         packet = self.pack_data(Packet.TEXTMESSAGE, payload)
        !           130:         self.transport.write(packet)
        !           131:
        !           132:     def move_user(self, channel_id, user_id):
        !           133:         state = mumble_protobuf.UserState()
        !           134:         state.session = user_id
        !           135:         state.channel_id = channel_id
        !           136:         payload = state.SerializeToString()
        !           137:         packet = self.pack_data(Packet.USERSTATE, payload)
        !           138:         self.transport.write(packet)
        !           139:
        !           140:     def mute_or_deaf(self, user_id, mute=True, deaf=True):
        !           141:         state = mumble_protobuf.UserState()
        !           142:         state.session = user_id
        !           143:         if user_id == self.session:
        !           144:             state.self_mute = mute
        !           145:             state.self_deaf = deaf
        !           146:         else:
        !           147:             state.mute = mute
        !           148:             state.deaf = deaf
        !           149:         payload = state.SerializeToString()
        !           150:         packet = self.pack_data(Packet.USERSTATE, payload)
        !           151:         self.transport.write(packet)
        !           152:
        !           153:     # Parse mumble protocol packets
        !           154:     def unpack_data(self, data):
        !           155:         p_type, p_length = struct.unpack(">hi", data[:6])
        !           156:         p_data = data[6:p_length+6]
        !           157:         parsed = getattr(mumble_protobuf, PACKET_NAMES[p_type])()
        !           158:
        !           159:         if p_type == Packet.UDPTUNNEL:
        !           160:             parsed = self.parse_voicedata(p_data)
        !           161:         else:
        !           162:             parsed.ParseFromString(p_data)
        !           163:
        !           164:         return p_type, parsed, data[p_length+6:]
        !           165:
        !           166:     def parse_voicedata(self, data):
        !           167:         p = VoicePacket()
        !           168:         header, = struct.unpack(">B", data[0])
        !           169:         p.type, p.target = header >> 5, header & 31
        !           170:         p.session, data = parse_varint(data[1:])
        !           171:         p.sequence, data = parse_varint(data)
        !           172:
        !           173:         # Swap to enable saving voice packets
        !           174:         # while data:
        !           175:         while False:
        !           176:             audio, = struct.unpack(">B", data[0])
        !           177:             a_terminator, a_length = audio >> 7, audio & 127
        !           178:             audio_data, data = data[1:a_length+1], data[a_length+1:]
        !           179:             p.frames.append(audio_data)
        !           180:             p.lengths.append(a_length)
        !           181:             if a_terminator == 0:
        !           182:                 break
        !           183:
        !           184:         return p
        !           185:
        !           186:     # Handles various interactions
        !           187:     def get_handlers(self):
        !           188:         handlers = {
        !           189:             1:  self.handle_udptunnel,
        !           190:             7:  self.handle_channelstate,
        !           191:             8:  self.handle_userremove,
        !           192:             9:  self.handle_userstate,
        !           193:             11: self.handle_textmessage
        !           194:         }
        !           195:         return handlers
        !           196:
        !           197:     def handle_udptunnel(self, p):
        !           198:         pass
        !           199:
        !           200:     def handle_channelstate(self, p):
        !           201:         pass
        !           202:
        !           203:     def handle_userremove(self, p):
        !           204:         pass
        !           205:
        !           206:     def handle_userstate(self, p):
        !           207:         pass
        !           208:
        !           209:     def handle_textmessage(self, p):
        !           210:         pass

CVSweb