#!/usr/bin/env python3 import struct import binascii from .packets_in import in_packets from .packets_out import out_packets class Login(object): """ Author: jak1 License: GPLv2+ State: Testing (Draft) Class Login: handles Login Packets (some packets can only get used in the right order!) socket: bound login server socket debugging: enabled if True, disabled otherwise NOTE: does the stored data allready have the right type? may i need to convert/cast them. """ def __init__(self, socket, debugging=False): self.socket = socket self.debugging = debugging def sendServerVersionRequest(self, version=26): """ FIXME: arg? (26 or 28? packet version or client version? [totaly confusing X_X]) """ out_packets[0x7530].send_data(self.socket, [version], self.debugging) def getServerVersion(self): """ TODO: WIP """ in_packets[0x7531].recv_data(self.socket, 1024, self.debugging) in_packets[0x7531].process_data() #['H', 'H', 'L', 'L', 'L', '*s'] def getUpdateHost(self): """ Function: getUpdateHost getting the updatehost URL returns: updatehost (str) """ in_packets[0x0063].recv_data(self.socket, 1024, self.debugging) in_packets[0x0063].process_data() return in_packets[0x0063].p_data_list[2] def sendLoginRegister(self, username, password, clientversion=26): """ Function: sendLoginRegister auth. a registred Useraccount with username and password username: login username password: login password clientversion: client packet version (default=26) different versions are may not supported rn. returns: None """ _flag = 0x03 out_packets[0x064].send_data( self.socket, [clientversion, bytes(username, "ascii"), bytes(password, "ascii"), _flag], self.debugging) def getCharLoginData(self): """ Function: getCharLoginData gets CharServer auth. data, and all char-servers TODO: store session_id_*, account_id, gender, server_name returns: servers (dict) structure: "session_id_p1", "session_id_p2", "account_id", "last_ip", "last_login", "gender", "char_server": [ "host", "port", "server_name", "current_online" ] """ in_packets[0x0ac4].recv_data(self.socket, 1024, self.debugging) in_packets[0x0ac4].process_data() server_len = 160 s_count = int(in_packets[0x0ac4].p_len / server_len) server = [{}] for x in range(s_count): offset = x * server_len host, port, name, online, twitter, twitter_flag = struct.unpack( "<4s H 20s H H H 128x", in_packets[0x0ac4].p_data_list[10][offset:offset + server_len]) host = "{}.{}.{}.{}".format(*(host)) server[x] = { "host": host, "port": port, "server_name": name, "current_online": online } servers = { "session_id_p1": in_packets[0x0ac4].p_data_list[2], "session_id_p2": in_packets[0x0ac4].p_data_list[4], "account_id": in_packets[0x0ac4].p_data_list[3], "last_ip": in_packets[0x0ac4].p_data_list[5], "last_login": in_packets[0x0ac4].p_data_list[6], "gender": in_packets[0x0ac4].p_data_list[8], "char_server": server } return servers def getLoginError(self): """ Function: getLoginError NOTE: ONLY CALL FROM LOGIN! traceback error codes for failed Login returns: ( 0x00 - The ID is not registered. 0x01 - Incorrect Password. 0x02 - The ID is expired. 0x03 - Rejected from Server. 0x04 - You have been blocked by the GM team. 0x05 - Client version is too low (client out of date). 0x06 - Your are temporarily prohibited from logging in. 0x07 - Server is jammed due to over populated. 0x08 - No MSG (actually, all states after 9 except 99 are No MSG, use only this) 0x63 - This ID has been completely erased. , Message ) (tuple(int, str)) """ in_packets[0x006a].recv_data(self.socket, 1024, self.debugging) in_packets[0x006a].process_data() return (in_packets[0x006a].p_data_list[2], in_packets[0x006a].p_data_list[3]) def getLoginError(self): """ Function: getLoginError NOTE: ONLY CALL FROM LOGIN! returns: tuple(id(int), error_msg(str)) """ in_packets[0x0081].recv_data(self.socket, 3, self.debugging) in_packets[0x0081].process_data() error_code = in_packets[0x0081].get_list_data()[1] errors = { 0: "Authentication failed.", 1: "No servers available.", 2: "Account allready in use.", 3: "Speed hack detected.", 4: "Server full.", 5: "Sorry, you are underaged.", 7: "", # just exit with 7 as exit_code 8: "Duplicated login.", 9: "To many connections from same ip.", 10: "Not paid for this time.", 11: "Pay suspended.", 12: "Pay changed.", 13: "Pay wrong ip.", 14: "Pay game room.", 15: "Disconnect forced by GM.", 16: "Ban japan refuse.", 17: "Ban japan refuse.", 18: "Remained other account.", 100: "Ip unfair.", # translation issue? 101: "Ip count all.", # ?! 102: "Ip count.", # ?! 103: "Memory.", 104: "Memory.", 105: "Han valid.", 106: "Ip limited access.", 107: "Over characters list.", 108: "Ip blocked.", 109: "Invalid password count.", 110: "Not allowed race.", 113: "Access restricted in hours 00:00 to 06:00.", 115: "You were banned." } if error_code not in errors: return (error_code, "Unknown connection error.") else: return (error_code, errors[error_code])