-
Notifications
You must be signed in to change notification settings - Fork 5
/
OutgoingPackets.py
307 lines (265 loc) · 10.3 KB
/
OutgoingPackets.py
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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
#(C) Marek Chrusciel,
# Jakub Kosinski,
# Marcin Krupowicz,
# Mateusz Strycharski
#
# $Id$
import time
import types
import sys
import struct
from HeaderPacket import GGHeader
from Networking import Connection
from GGConstans import *
import Helpers
from Helpers import Enum
GGOutgoingPackets = Enum({
"GGNewStatus":0x0002, #Zmiana statusu
"GGPing":0x0008, #Ping
"GGSendMsg":0x000b, #Wyslanie wiadomosci
"GGLogin":0x000c, #Logowanie sie przed GG 6.0
"GGAddNotify":0x000d, #Dodanie do listy kontaktow
"GGRemoveNotify":0x000e, #Usuniecie z listy kontaktow
"GGNotifyFirst":0x000f, #Poczatkowy fragment listy kontaktow wiekszej niz 400 wpisow
"GGNotifyLast":0x00010, #Ostatni fragment listy kontaktow
"GGListEmpty":0x0012, #Nasza lista kontaktow jest pusta
"GGLoginExt":0x0013, #Logowanie przed GG 6.0
"GGPubDir50Request":0x0014, #Zapytanie katalogu publicznego
"GGLogin60":0x0015, #Logowanie
"GGUserListRequest":0x0016, #Zapytanie listy kontaktow na serwerze
"GGLogin70":0x0019, #Logowanie
"GGUserlistRequest":0x0016 #Wysylanie kontaktow do serwera Gadu-Gadu
})
class GGOutgoingPacket(object):
"""
"Abstrakcyjna" klasa pakietow wysylanych do serwera
"""
def send(self):
pass
class GGLogin(GGOutgoingPacket):
"""
Pakiet ten wysylamy do serwera, zeby sie zalogowac
"""
def __init__(self, uin, password, status, seed, description = "", local_ip = "127.0.0.1", local_port = 1550, \
external_ip = "127.0.0.1", external_port = 0, image_size = 255, time = 0):
"""
uin - numer gadu-gadu (int)
password - haslo (string)
status - status poczatkowy (GGStatus)
seed - seed z pakietu GGWelcome (int)
"""
assert type(uin) == types.IntType
assert type(password) == types.StringType
#assert type(status) in GGStatus
#assert type(seed) == types.IntType or type(seed) == types.LongType
assert type(description) == types.StringType and len(description) <= 70
assert type(local_ip) == types.StringType
assert type(local_port) == types.IntType
assert type(external_ip) == types.StringType
assert type(external_port) == types.IntType
assert type(time) == types.IntType
assert type(image_size) == types.IntType
self.uin = uin
self.password = password
self.status = status
self.seed = seed
self.local_ip = local_ip
self.local_port = local_port
self.description = description
self.external_ip = external_ip
self.external_port = external_port
self.image_size = image_size
self.time = time
self.version = 0x25 # GG 7.7
def send(self, connection):
assert type(connection) == Connection
"""
data = struct.pack("<IBIIIBIHIHBB%dsI" % (len(self.description) + 1),
#data = struct.pack("<IB64sIIBIHIHBB%dsI" % (len(self.description) + 1),
self.uin,
0x01,
Helpers.gg_login_hash(self.password, self.seed),
self.status,
self.version,
0x00,
Helpers.ip_to_int32(self.local_ip),
self.local_port,
Helpers.ip_to_int32(self.external_ip),
self.external_port,
self.image_size,
0xbe,
self.description,
self.time)
connection.send(repr(GGHeader(GGOutgoingPackets.GGLogin, len(data))) + data)
"""
data = struct.pack("<IIIIBIhIhBB%dsI" % (len(self.description) + 1),
self.uin, Helpers.gg_login_hash(self.password, self.seed), self.status, self.version, 0x00,
Helpers.ip_to_int32(self.local_ip), self.local_port, Helpers.ip_to_int32(self.external_ip), self.external_port,
self.image_size, 0xbe, self.description, self.time)
connection.send(repr(GGHeader(GGOutgoingPackets.GGLogin60, len(data))) + data)
class GGNewStatus(GGOutgoingPacket):
"""
Pakiet ten wysylamy do serwera, zeby zmienic status
"""
def __init__(self, status, description = '', time = None):
"""
status - status (GGStatus)
description - opis statusu (string)
time - czas w sekundach od 1.01.1970
"""
assert type(status) == types.IntType
assert type(description) == types.StringType and len(description) <= 70
#assert type(time) == types.IntType or type(time) == types.LongTime
self.status = status
self.description = description
self.time = time
def send(self, connection):
assert type(connection) == Connection
if self.status == GGStatuses.Avail or self.status == GGStatuses.NotAvail or self.status == GGStatuses.Busy or self.status == GGStatuses.Invisible or self.status == GGStatuses.Blocked:
data = struct.pack("<I", self.status)
else: # status z opisem
if self.time == None: #bez czasu
data = struct.pack("<I%ds" % (len(self.description),), self.status, self.description)
else:
data = struct.pack("<I%dsBI" % (len(self.description), ), self.status, self.description, 0x00, self.time)
connection.send(repr(GGHeader(GGOutgoingPackets.GGNewStatus, len(data))) + data)
class GGSendMsg(GGOutgoingPacket):
"""
Pakiet wysylamy do serwera, zeby wyslac wiadomosc
"""
def __init__(self, rcpt, msg, seq = 0, msg_class = 0x0004):
"""
rcpt - numer odbiorcy
seq - numer serwencyjny wiadomosci
msg_class - klasa wiadomosci
msg - wiadomosc
"""
assert type(rcpt) == types.IntType and rcpt > 0
assert type(seq) == types.IntType
assert type(msg_class) == types.IntType
assert type(msg) == types.StringType and len(msg) <= 2000
self.rcpt = rcpt
self.seq = seq
self.msg_class = msg_class
self.msg = msg
def send(self, connection):
assert type(connection) == Connection
data = struct.pack("<III%ds" % (len(self.msg) + 1), self.rcpt, self.seq, self.msg_class, self.msg)
connection.send(repr(GGHeader(GGOutgoingPackets.GGSendMsg, len(data))) + data)
class GGPing(GGOutgoingPacket):
"""
Co jakis czas trzeba wysylac do serwera GG pakiet GGPing. W przeciwnym przypadku, serwer nas rozlaczy.
"""
def __init__(self):
pass
def send(self, connection):
assert type(connection) == Connection
connection.send(repr(GGHeader(GGOutgoingPackets.GGPing, 0)))
class GGListEmpty(GGOutgoingPacket):
"""
Jesli nie mamy nikogo na liscie kontaktow, wysylamy ten pakiet - np. zaraz po zalogowaniu sie
"""
def __init__(self):
pass
def send(self, connection):
assert type(connection) == Connection
connection.send(repr(GGHeader(GGOutgoingPackets.GGListEmpty, 0)))
class GGNotifyFirst(GGOutgoingPacket):
"""
Pierwsze wpisy (kazde po 400 kontaktow zawieraja) listy kontaktow, ktora wysylamy serwerowi po polaczeniu.
"""
def __init__(self, gg_notify_list):
"""
gg_notify_list list to lista krotek postaci: (uin, typ_uzytkownika)
"""
assert type(gg_notify_list) == types.ListType
for notify in gg_notify_list:
assert type(notify) == types.TupleType
assert len(notify) == 2
assert type(notify[0]) == types.IntType and type(notify([1])) in GGUserTypes
assert len(gg_notify_list) == 400
self.__gg_notify_list = gg_notify_list
def send(self, connection):
assert type(connection) == Connection
data = ""
for notify in self.__gg_notify_list:
data += struct.pack("<IB", notify[0], notify[1])
connection.send(repr(GGHeader(GGOutgoingPackets.GGNotifyFirst, len(data))) + data)
class GGNotifyLast(GGOutgoingPacket):
"""
Ostatnie wpisy listy kontaktow (maksymalnie 400), ktore wysylamy zaraz po podlaczaniu. Jesli lista kontaktow
zawiera <= 400 kontaktow to wysylamy jedynie ten pakiet. Jesli wiecej, to wysylamy najpierw pakiety GGNotifyFirst,
a na koncu ten pakiet
"""
def __init__(self, gg_notify_list):
"""
gg_notify_list to lista krotek postaci: (uin, typ_uzytkownika)
"""
assert type(gg_notify_list) == types.ListType
for notify in gg_notify_list:
assert type(notify) == types.TupleType
assert len(notify) == 2
#assert type(notify[0]) == types.IntType and type(notify[1]) in GGUserTypes
assert len(gg_notify_list) <= 400 #TODO: <= czy < ??? W protokole jest niejasno napisane... :(
self.__gg_notify_list = gg_notify_list
def send(self, connection):
assert type(connection) == Connection
data = ""
for notify in self.__gg_notify_list:
data += struct.pack("<IB", int(notify[0]), notify[1])
connection.send(repr(GGHeader(GGOutgoingPackets.GGNotifyLast, len(data))) + data)
class GGAddNotify(GGOutgoingPacket):
"""
Jesli w trakcie dzialania sesji chcemy kogos dodac do kontaktow, to wysylamy do serwera infomacje o nim.
Po wyslaniu tego pakietu, serwer bezdie nas informowal o zmianach statusu tego kontaktu.
"""
def __init__(self, uin, user_type = 0x3):
self.uin = uin
self.user_type = user_type
def send(self, connection):
assert type(connection) == Connection
data = struct.pack("<IB", self.uin, self.user_type & 0xff)
connection.send(repr(GGHeader(GGOutgoingPackets.GGAddNotify, len(data))) + data)
class GGRemoveNotify(GGOutgoingPacket):
"""
Jesli w trakcie dzialania sesji chcemy kogos usunac z listy kontaktow, to wysylamy do serwera infomacje o nim.
Po wyslaniu tego pakietu, serwer przestanie nas informowac o zmianach statusu tego kontaktu.
Jesli podamy user_type (patrz protokol), to mozemy zmienic rodzaj uzytkowinka (niekoniecznie usuwajac go z serwerowej listy kontaktow).
"""
def __init__(self, uin, user_type = 0x0):
self.uin = uin
self.user_type = user_type
def send(self, connection):
assert type(connection) == Connection
data = struct.pack("<IB", self.uin, self.user_type & 0xff)
connection.send(repr(GGHeader(GGOutgoingPackets.GGRemoveNotify, len(data))) + data)
class GGPubDir50Request(GGOutgoingPacket):
"""
Pakiet sluzacy do odpytywania katalogu publicznego
"""
def __init__(self, request, reqtype = GGPubDirTypes.Search):
assert type(request) == types.StringType or type(request) == types.DictType
if type(request) == types.StringType:
self.request = request
else:
self.request = Helpers.dict_to_request(request)
self.reqtype = reqtype
self.seq = int(time.time())
def send(self, connection):
assert type(connection) == Connection
data = struct.pack("<BI%ds" % (len(self.request) + 1), self.reqtype, self.seq, self.request)
connection.send(repr(GGHeader(GGOutgoingPackets.GGPubDir50Request, len(data))) + data)
class GGUserListRequest(GGOutgoingPacket):
"""
Pakiet sluzacy do wysylania listy kontaktow na serwer Gadu-Gadu
TODO: poprawa, bo to chyba nie dziala
"""
def __init__(self, reqtype, request):
assert type(request) == types.StringType
assert reqtype in GGUserListTypes
self.reqtype = reqtype
self.request = request
def send(self, connection):
assert type(connection) == Connection
data = struct.pack("<B%ds" % (len(self.request) + 1), self.reqtype, self.request)
connection.send(repr(GGHeader(GGOutgoingPackets.GGUserlistRequest, len(data))) + data)