1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
|
#!/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])
|