def _recv_command(self, decrypt=True): """ .. todo:: rewrite """ recv_size = self._recv_to_buff() if len( self._recv_buff ) < 5 and not self._decrypted_header: # all packets are terminated by 0x00 return None, None if not self._decrypted_header: # decrypt header if decrypt: first4 = self._crypto.decrypt(self._recv_buff[:4]) else: first4 = self._recv_buff[:4] headerbuff = bytebuff(first4) self._recv_buff = self._recv_buff[4:] size_1 = headerbuff.get(">B") if size_1 & 0x80 and self._ver >= EXPANSION_WOTLK: #big packet if decrypt: headerbuff += self._crypto.decrypt(self._recv_buff[:1]) else: headerbuff += self._recv_buff[:1] self._recv_buff = self._recv_buff[1:] size_2 = headerbuff.get(">H") size = ((size_1 ^ 0x80) << 16) + size_2 - 2 else: # little packet size_2 = headerbuff.get(">B") size = (size_1 << 8) + size_2 - 2 cmd = headerbuff.get("H") self._decrypted_header = (size, cmd) if self._decrypted_header: size = self._decrypted_header[0] cmd = self._decrypted_header[1] if len(self._recv_buff) < size: return None, None data = self._recv_buff[:size] self._recv_buff = self._recv_buff[size:] if self._ver >= EXPANSION_CATA and cmd & COMPRESSED_OPCODE_MASK: cmd ^= COMPRESSED_OPCODE_MASK data = self._zlib_stream.decompress(data[4:]) buff = bytebuff(data) else: buff = bytebuff(data) self._decrypted_header = () logging.getLogger("tclib").debug("WORLD: recv cmd: %s; data: %s", hex(cmd), buff) return cmd, buff return None, None
def _worker(self): self._connect() # SMSG_AUTH_CHALLENGE if self._ver >= EXPANSION_CATA: #rewrite self._connection.recv(50, socket.MSG_WAITALL) if self._ver == EXPANSION_CATA: self._send( "\x00\x2fWORLD OF WARCRAFT CONNECTION - CLIENT TO SERVER") else: self._send( "\x30\x00WORLD OF WARCRAFT CONNECTION - CLIENT TO SERVER\00" ) buff = bytebuff(self._connection.recv(41, socket.MSG_WAITALL)) elif self._ver == EXPANSION_WOTLK: buff = bytebuff(self._connection.recv(44, socket.MSG_WAITALL)) else: buff = bytebuff(self._connection.recv(8, socket.MSG_WAITALL)) print len(buff.data) size = buff.get(">H") # wotlk - 42, cata - 39; tbc - 6 cmd = buff.get("H") print cmd if self._ver == EXPANSION_CATA: cmd = opcode_translate_cata_wotlk(cmd) elif self._ver == EXPANSION_PANDA: cmd = opcode_translate_panda_wotlk(cmd) print cmd if cmd != SMSG_AUTH_CHALLENGE: raise StreamBrokenError() buff.cut() self._world._handle_auth_challange(cmd, buff) # CMSG_AUTH_SESSION cmd, buff = self._send_queue.get() self._send_command(cmd, buff, False) self._connection.setblocking(0) while 1: time.sleep(NETWORK_LOOP_SLEEP) while 1: cmd, buff = self._recv_command() if cmd == None: break elif cmd == SMSG_NAME_QUERY_RESPONSE or cmd == CATA_SMSG_NAME_QUERY_RESPONSE: # little hack, world threat is now probably blocked self._world._handle_name_query_response(cmd, buff) self._recv_queue.put((cmd, buff)) while 1: try: cmd, buff = self._send_queue.get_nowait() self._send_command(cmd, buff) except Queue.Empty: break
def _recv_command(self, decrypt = True): """ .. todo:: rewrite """ recv_size = self._recv_to_buff() if len(self._recv_buff) < 5 and not self._decrypted_header: # all packets are terminated by 0x00 return None, None if not self._decrypted_header: # decrypt header if decrypt: first4 = self._crypto.decrypt(self._recv_buff[:4]) else: first4 = self._recv_buff[:4] headerbuff = bytebuff(first4) self._recv_buff = self._recv_buff[4:] size_1 = headerbuff.get(">B") if size_1 & 0x80 and self._ver >= EXPANSION_WOTLK: #big packet if decrypt: headerbuff += self._crypto.decrypt(self._recv_buff[:1]) else: headerbuff += self._recv_buff[:1] self._recv_buff = self._recv_buff[1:] size_2 = headerbuff.get(">H") size = ((size_1 ^ 0x80) << 16) + size_2 - 2 else: # little packet size_2 = headerbuff.get(">B") size = (size_1 << 8) + size_2 - 2 cmd = headerbuff.get("H") self._decrypted_header = (size, cmd) if self._decrypted_header: size = self._decrypted_header[0] cmd = self._decrypted_header[1] if len(self._recv_buff) < size: return None, None data = self._recv_buff[:size] self._recv_buff = self._recv_buff[size:] if self._ver >= EXPANSION_CATA and cmd & COMPRESSED_OPCODE_MASK: cmd ^= COMPRESSED_OPCODE_MASK data = self._zlib_stream.decompress(data[4:]) buff = bytebuff(data) else: buff = bytebuff(data) self._decrypted_header = () logging.getLogger("tclib").debug("WORLD: recv cmd: %s; data: %s", hex(cmd), buff) return cmd, buff return None, None
def send_channel_list(self, name = None): """ CMSG_CHANNEL_LIST (CMSG_CHANNEL_DISPLAY_LIST) Parameters ---------- name : str channel name; if None send for all joined channels """ if name == None: for channel in self.get_all_channels(): assert(channel.name != None) self.send_channel_list(channel.name) return assert(self._ver < EXPANSION_CATA or len(name) < 2**8) buff = bytebuff() name = name.lower() if self._ver >= EXPANSION_CATA: buff.add("<B", len(name)) buff.add_raw(name) else: buff.add("S", name) self._send(CMSG_CHANNEL_LIST, buff)
def send_join_channel(self, name, password = ""): """ CMSG_JOIN_CHANNEL Parameters ---------- name : str password : str """ name = name.lower() buff = bytebuff() if self._ver >= EXPANSION_CATA: buff.add("I", 0) buff.add_bit(0) # unknown buff.add_bit(0) # unknown buff.add("8t", len(name)) buff.add("8t", len(password)) buff.fill_byte() buff.add("k", name) buff.add("k", password) elif self._ver >= EXPANSION_TBC: buff.add_zeros(6) buff.add("S", name.lower()) buff.add("S", password) else: buff.add("S", name.lower()) buff.add("S", password) self._send(CMSG_JOIN_CHANNEL, buff)
def _handle_guild_query(self, cmd, buff): """ SMSG_GUILD_QUERY_RESPONSE Returns ---------- guild_id : int player_guild : bool guild_name : str rank_names : list of str """ if self._ver >= EXPANSION_CATA: return # TODO: implement buff = bytebuff() guild_id = buff.get("I") guild_name = buff.get("S") player_guild = False if guild_id == self._my_player.guild_id: player_guild = True rank_names = [] guild_ranks_max_count = 10 for i in range(guild_ranks_max_count): rank_name = buff.get("S") if not rank_name: break rank_names.append() return guild_id, player_guild, guild_name, rank_names
def _worker(self): self._connect() # SMSG_AUTH_CHALLENGE if self._ver >= EXPANSION_CATA: #rewrite self._connection.recv(50, socket.MSG_WAITALL) if self._ver == EXPANSION_CATA: self._send("\x00\x2fWORLD OF WARCRAFT CONNECTION - CLIENT TO SERVER") else: self._send("\x30\x00WORLD OF WARCRAFT CONNECTION - CLIENT TO SERVER\00") buff = bytebuff(self._connection.recv(41, socket.MSG_WAITALL)) elif self._ver == EXPANSION_WOTLK: buff = bytebuff(self._connection.recv(44, socket.MSG_WAITALL)) else: buff = bytebuff(self._connection.recv(8, socket.MSG_WAITALL)) print len(buff.data) size = buff.get(">H") # wotlk - 42, cata - 39; tbc - 6 cmd = buff.get("H") print cmd if self._ver == EXPANSION_CATA: cmd = opcode_translate_cata_wotlk(cmd) elif self._ver == EXPANSION_PANDA: cmd = opcode_translate_panda_wotlk(cmd) print cmd if cmd != SMSG_AUTH_CHALLENGE: raise StreamBrokenError() buff.cut() self._world._handle_auth_challange(cmd, buff) # CMSG_AUTH_SESSION cmd, buff = self._send_queue.get() self._send_command(cmd, buff, False) self._connection.setblocking(0) while 1: time.sleep(NETWORK_LOOP_SLEEP) while 1: cmd, buff = self._recv_command() if cmd == None: break elif cmd == SMSG_NAME_QUERY_RESPONSE or cmd == CATA_SMSG_NAME_QUERY_RESPONSE: # little hack, world threat is now probably blocked self._world._handle_name_query_response(cmd, buff) self._recv_queue.put((cmd, buff)) while 1: try: cmd, buff = self._send_queue.get_nowait() self._send_command(cmd, buff) except Queue.Empty: break
def send_contact_list(self): """ CMSG_CONTACT_LIST """ buff = bytebuff() buff.add("I", 1) #unknown, always 1 self._send(CMSG_CONTACT_LIST, buff)
def send_auction_list_items(self, listfrom, searchedname = AUCTION_SEARCHEDNAME_ALL, levelmin = AUCTION_LEVELMIN_ALL, levelmax = AUCTION_LEVELMAX_ALL, auction_slot_id = AUCTION_FILTERS_ALL, auction_main_category = AUCTION_FILTERS_ALL, auction_sub_category = AUCTION_FILTERS_ALL, quality = AUCTION_FILTERS_ALL, only_usable = False, get_all = False): """ CMSG_AUCTION_LIST_ITEMS Send auction list items. listfrom : int Page number searchedname : string AUCTION_SEARCHEDNAME_ALL for all levelmin : int AUCTION_LEVELMIN_ALL for all levelmax : int AUCTION_LEVELMAX_ALL for all auction_slot_id : int AUCTION_FILTERS_ALL for all auction_main_category : int AUCTION_FILTERS_ALL for all auction_sub_category : int AUCTION_FILTERS_ALL for all quality : int AUCTION_FILTERS_ALL for all only_usable : bool get_all : bool """ if self._ver != EXPANSION_WOTLK: raise NotImplementedError # TODO: implement if not self._auction_ready: raise SendAuctionHelloFirst buff = bytebuff() buff.add("Q", self._auctioneer_guid) buff.add("I", listfrom) buff.add("S", searchedname) buff.add("B", levelmin) buff.add("B", levelmax) buff.add("I", auction_slot_id) buff.add("I", auction_main_category) buff.add("I", auction_sub_category) buff.add("I", quality) buff.add("B", int(only_usable)) buff.add("B", int(get_all)) buff.add("B", 0) # unknown self._send(CMSG_AUCTION_LIST_ITEMS, buff)
def send_played_time(self, show = True): """ CMSG_PLAYED_TIME Parameters ---------- show : bool """ buff = bytebuff() buff.add("B", int(show)) self._send(CMSG_PLAYED_TIME, buff)
def send_add_ignore(self, player_name): """ CMSG_ADD_IGNORE Parameters ---------- player_name : str """ buff = bytebuff() buff.add("S", player_name) self._send(CMSG_ADD_IGNORE, buff)
def _send_command(self, cmd, buff, encrypt = True): data = buff.data assert(len(data) < 2**16-7) logging.getLogger("tclib").debug("WORLD: sending cmd: %s; data: %s", hex(cmd), buff) headerbuff = bytebuff() headerbuff.add(">H", len(data) + 4) headerbuff.add("H", cmd) headerbuff.add_zeros(2) header = headerbuff.data if encrypt: header = self._crypto.encrypt(header) self._send(header + data)
def _send_command(self, cmd, buff, encrypt=True): data = buff.data assert (len(data) < 2**16 - 7) logging.getLogger("tclib").debug("WORLD: sending cmd: %s; data: %s", hex(cmd), buff) headerbuff = bytebuff() headerbuff.add(">H", len(data) + 4) headerbuff.add("H", cmd) headerbuff.add_zeros(2) header = headerbuff.data if encrypt: header = self._crypto.encrypt(header) self._send(header + data)
def send_auction_hello(self, auctioneer_guid): """ MSG_AUCTION_HELLO Send auction hello. Parameters ---------- auctioneer_guid : int """ if self._ver != EXPANSION_WOTLK: raise NotImplementedError # TODO: implement buff = bytebuff() buff.add("Q", auctioneer_guid) self._send(MSG_AUCTION_HELLO, buff)
def send_guild_query(self, guild_id=None): """ CMSG_GUILD_QUERY Parameters ---------- guild_id : int """ if self._ver >= EXPANSION_CATA: raise NotImplementedError # TODO: implement if guild_id == None: guild_id = self._my_player.guild_id buff = bytebuff() buff.add("I", guild_id) self._send(CMSG_GUILD_QUERY, buff)
def send_guild_query(self, guild_id = None): """ CMSG_GUILD_QUERY Parameters ---------- guild_id : int """ if self._ver >= EXPANSION_CATA: raise NotImplementedError # TODO: implement if guild_id == None: guild_id = self._my_player.guild_id buff = bytebuff() buff.add("I", guild_id) self._send(CMSG_GUILD_QUERY, buff)
def send_leave_channel(self, name): """ CMSG_LEAVE_CHANNEL Parameters ---------- name : str """ name = name.lower() buff = bytebuff() if self._ver >= EXPANSION_CATA: buff.add("I", 0) # unknown buff.add("8t", len(name)) buff.add("k", name) else: buff.add_zeros(4) buff.add("S", name) self._send(CMSG_LEAVE_CHANNEL, buff)
def send_who(self, minlevel = 0, maxlevel = 100, racemask = 0xFFFFFFFF, classmask = 0xFFFFFFFF, player_name = "", guild_name = "", user_strings = None, zones = None): """ CMSG_WHO Parameters ---------- minlevel : int maxlevel : int racemask : int classmask : int player_name : str guild_name : str user_strings : list of strs zones : list of ints """ if user_strings == None: user_strings = () if zones == None: zones = () assert(len(user_strings) <= 4) assert(len(zones) <= 10) buff = bytebuff() buff.add("I", minlevel) buff.add("I", maxlevel) buff.add("S", player_name) buff.add("S", guild_name) buff.add("I", racemask) buff.add("I", classmask) buff.add("I", len(zones)) for i in zones: buff.add("I", i) buff.add("I", len(user_strings)) for string in user_strings: buff.add("S", string) self._send(CMSG_WHO, buff)
def send_message_chat(self, msg_type, msg, to = ""): """ CMSG_MESSAGECHAT Send chat message. Parameters ---------- msg_type : int Implemented: CHAT_MSG_WHISPER, CHAT_MSG_CHANNEL, CHAT_MSG_SAY, CHAT_MSG_PARTY, CHAT_MSG_RAID, CHAT_MSG_GUILD, CHAT_MSG_OFFICER, CHAT_MSG_YELL, CHAT_MSG_WHISPER, CHAT_MSG_CHANNEL msg : str msg must be less than 256 characters to : str Required if msg_type is CHAT_MSG_WHISPER or CHAT_MSG_CHANNEL Raises ---------- NotImplementedError If msg_type is not implemented. MessageIsTooLong If len(msg) > 255 """ if len(msg) > 255: raise MessageIsTooLong() if msg_type == CHAT_MSG_WHISPER and self._ver < EXPANSION_CATA: lang = LANG_GLOBAL else: lang = self._my_player.default_lang buff = bytebuff() if msg_type in (CHAT_MSG_WHISPER, CHAT_MSG_CHANNEL): assert(to) if self._ver >= EXPANSION_CATA: buff.add("I", lang) buff.add("10t", len(to)) buff.add("9t", len(msg)) buff.fill_byte() if msg_type == CHAT_MSG_WHISPER: buff.add_raw(to) buff.add_raw(msg) if msg_type == CHAT_MSG_CHANNEL: buff.add_raw(msg) buff.add_raw(to) cmd = msg_type_translate_wotlk_cata(msg_type) self._send(cmd, buff, False) else: if self._ver == EXPANSION_VANILLA: msg_type = msg_type_translate_wotlk_vanilla(msg_type) buff.add("I", msg_type) buff.add("I", lang) buff.add("S", to) buff.add("S", msg) self._send(CMSG_MESSAGECHAT, buff) return if msg_type in (CHAT_MSG_SAY, CHAT_MSG_PARTY, CHAT_MSG_RAID, CHAT_MSG_GUILD, CHAT_MSG_OFFICER, CHAT_MSG_YELL): if self._ver >= EXPANSION_CATA: buff.add("I", lang) buff.add("9t", len(msg)) buff.fill_byte() buff.add_raw(msg) cmd = msg_type_translate_wotlk_cata(msg_type) self._send(cmd, buff, False) else: if self._ver == EXPANSION_VANILLA: msg_type = msg_type_translate_wotlk_vanilla(msg_type) buff.add("I", msg_type) buff.add("I", lang) buff.add("S", msg) self._send(CMSG_MESSAGECHAT, buff) return raise NotImplementedError()