[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

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