rgadu 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/gg/dccserver.rb +3 -1
- data/lib/gg.rb +124 -93
- metadata +2 -2
data/lib/gg/dccserver.rb
CHANGED
@@ -28,6 +28,7 @@ class DCCServer
|
|
28
28
|
type=packet_raw.unpack('L')[0]
|
29
29
|
if type==0x03
|
30
30
|
if filename=@queue[client_uin]
|
31
|
+
@queue.delete(client_uin)
|
31
32
|
init_send(client_uin, session, filename)
|
32
33
|
end
|
33
34
|
elsif type==0x02
|
@@ -36,6 +37,7 @@ class DCCServer
|
|
36
37
|
elsif @queue[packet_raw]
|
37
38
|
code=packet_raw
|
38
39
|
direction, filename, filesize, offset = @queue[code]
|
40
|
+
@queue.delete(code)
|
39
41
|
if direction == :out
|
40
42
|
session.write(code)
|
41
43
|
begin
|
@@ -110,7 +112,7 @@ class DCCServer
|
|
110
112
|
if type==0x01
|
111
113
|
packet_raw = session.read(332) or return
|
112
114
|
packet_body = packet_raw.unpack('LLLLLLLLLLLLLLa262a14')
|
113
|
-
filename = packet_body[14].sub(/\x00
|
115
|
+
filename = packet_body[14].sub(/\x00.*/m, '').sub(%r{.*/}, '')
|
114
116
|
filesize = packet_body[11]
|
115
117
|
if @prepare_recv and local_filename=@prepare_recv.call(client_uin, filename, filesize)
|
116
118
|
if local_filename.class == Array
|
data/lib/gg.rb
CHANGED
@@ -21,13 +21,15 @@ class GG
|
|
21
21
|
:invisible => 0x16,
|
22
22
|
:notavail => 0x15}
|
23
23
|
VERSION = {0x18 => '5.0', 0x19 => '5.0', 0x1b => '5.0', 0x1c => '5.7', 0x1e => '5.7',
|
24
|
-
0x20 => '6.0', 0x21 => '6.0', 0x22 => '6.0',
|
25
|
-
0x25 => '7.0', 0x26 => '7.0', 0x27 => '7.0', 0x28 => '7.5', 0x29 => '7.6', 0x2a => '7.7'}
|
24
|
+
0x20 => '6.0', 0x21 => '6.0', 0x22 => '6.0',
|
25
|
+
0x24 => '7.0', 0x25 => '7.0', 0x26 => '7.0', 0x27 => '7.0', 0x28 => '7.5', 0x29 => '7.6', 0x2a => '7.7'}
|
26
26
|
TO_GENDER = {:male => '2', :female => '1'}
|
27
27
|
PATTERN = {0x02 => 'LLa*',
|
28
28
|
0x0f => 'LCLSCCCa*',
|
29
|
+
0x17 => 'LCLSCCCa*',
|
29
30
|
0x0c => 'LCLSLSa*',
|
30
31
|
0x11 => 'LCLSCCCCa*',
|
32
|
+
0x18 => 'LCLSCCCCa*',
|
31
33
|
0x0e => 'CLa*',
|
32
34
|
0x0a => 'LLLLa*',
|
33
35
|
0x23 => 'La8',
|
@@ -36,42 +38,64 @@ class GG
|
|
36
38
|
0x1f => 'LLa8a21a43'}
|
37
39
|
|
38
40
|
=begin rdoc
|
39
|
-
Tworzy nowy obiekt GG i loguje sie na serwerze
|
41
|
+
Tworzy nowy obiekt GG i loguje sie na serwerze uzywajac numeru *uin* i hasla *password*. Dodatkowe parametry to: :server => serwer GG, :port => port na serwerze GG, :dccport => port dla polaczen bezposrednich, :contacts => tablica z lista kontaktow, :version => wersja protokolu.
|
40
42
|
=end
|
41
|
-
def initialize(uin, password,
|
43
|
+
def initialize(uin, password, params={})
|
44
|
+
server = params[:server] || '217.17.45.146'
|
45
|
+
port = params[:port] || 8074
|
46
|
+
dccport = params[:dccport]
|
47
|
+
contacts = params[:contacts] || []
|
48
|
+
version = (params[:version] || 6.0).to_f
|
42
49
|
@uin=uin
|
43
50
|
@dccport=dccport
|
44
51
|
@socket=TCPSocket.new(server, port)
|
45
52
|
type, length = read_header
|
46
53
|
if type!=0x01
|
47
54
|
raise "Packet not recognized"
|
48
|
-
end
|
55
|
+
end
|
49
56
|
seed=read_body(length, 'L')[0]
|
50
|
-
|
51
|
-
if dccport>0
|
57
|
+
if dccport
|
52
58
|
@dcc = DCCServer.new(dccport, uin)
|
53
59
|
localip=@socket.addr[3].split('.').collect {|x| x.to_i }.pack('C4').unpack('L')[0]
|
54
60
|
else
|
55
61
|
localip=0
|
56
62
|
end
|
57
|
-
|
63
|
+
if version >= 7.7
|
64
|
+
protocol = 0x2a
|
65
|
+
elsif version >= 7.6
|
66
|
+
protocol = 0x29
|
67
|
+
elsif version >= 7
|
68
|
+
protocol = 0x24
|
69
|
+
else
|
70
|
+
protocol = 0x20
|
71
|
+
end
|
72
|
+
if version >= 7
|
73
|
+
hash = Digest::SHA1.digest(password + [seed].pack('L'))
|
74
|
+
write(0x19, 'LCa64LLCLSLSCC', uin, 0x02, hash, 0x02, protocol, 0x00, localip, dccport, localip, dccport, 0x00, 0xbe)
|
75
|
+
else
|
76
|
+
hash = gg_login_hash(password, seed)
|
77
|
+
write(0x15, 'LLLLCLSLSCC', uin, hash, 0x02, 0x20, 0x00, localip, dccport, localip, dccport, 0x00, 0xbe)
|
78
|
+
end
|
58
79
|
type, length = read_header
|
59
80
|
read_body(length)
|
60
81
|
unless type==0x03 or type==0x14
|
61
82
|
raise "Authorization failed"
|
62
83
|
end
|
63
|
-
if contacts
|
64
|
-
|
84
|
+
if contacts.length > 0
|
85
|
+
contactpacket = []
|
86
|
+
contacts.each {|contact| contactpacket.push(contact, 0x03) }
|
87
|
+
write(0x10, 'LC'*contacts.length, *contactpacket)
|
65
88
|
else
|
66
89
|
write(0x12, '')
|
67
90
|
end
|
68
91
|
@action, @status, @search_reply, @dcc_code, @dcc_action, @dcc_client_action = {}, {}, {}, [], {}, {}
|
92
|
+
contacts.each {|contact| @status[contact] = {:status => :notavail} }
|
69
93
|
@action_thread, @dcc_client, @dcc_client_thread = [], [], []
|
70
94
|
@action[0x0a] = lambda {|sender, seq, time, cl, message| msg_received(sender, seq, time, cl, message) }
|
71
95
|
@action[0x02] = lambda {|uin, status, description| status_changed(uin, status, description) }
|
72
|
-
@action[0x0f] = lambda {|uin, status, ip, port, version, x, y, description| status_changed(uin, status, description, ip, port, version) }
|
96
|
+
@action[0x0f] = @action[0x17] = lambda {|uin, status, ip, port, version, x, y, description| status_changed(uin, status, description, ip, port, version) }
|
73
97
|
@action[0x0c] = lambda {|uin, status, ip, port, version, x, description| status_changed(uin, status, description, ip, port, version) }
|
74
|
-
@action[0x11] = lambda {|uin, status, ip, port, version, imgsize, x, descsize, description| status_changed(uin, status, description, ip, port, version) }
|
98
|
+
@action[0x11] = @action[0x18] = lambda {|uin, status, ip, port, version, imgsize, x, descsize, description| status_changed(uin, status, description, ip, port, version) }
|
75
99
|
@action[0x0e] = lambda {|type, seq, response| @search_reply[seq] = response }
|
76
100
|
@action[0x23] = lambda {|type, code| @dcc_code << code }
|
77
101
|
@action[0x21] = lambda {|uin, code, offset, x| @dcc_action[code].call(offset) if @dcc_action[code] }
|
@@ -182,80 +206,59 @@ Wyszukiwanie w katalogu publicznym. *params* moze byc numerem GG lub tablica aso
|
|
182
206
|
end
|
183
207
|
|
184
208
|
=begin rdoc
|
185
|
-
Wysyla plik *filename* do *uin*.
|
209
|
+
Wysyla plik *filename* do *uin*. Jesli dolaczono blok kodu, blok ten bedzie wywolywany podczas wysylania pliku. Blok przyjmuje jeden parametr - aktualn� pozycj� pliku w bajtach, symbol :rejected je�li po��czenie zosta�o odrzucone lub :aborted w przypadku przerwania transferu. Funkcja w zaleznosci od wersji protokolu DCC zwraca kod transferu lub numer GG odbiorcy.
|
186
210
|
=end
|
187
211
|
def dcc_request(uin, filename, hash=nil, &callback)
|
188
|
-
raise "
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
if
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
if @socket.addr[3] =~ /^(10\.|172\.16\.|192\.168\.)/
|
215
|
-
@dcc_client_action[code] = lambda do |ip, port|
|
216
|
-
@dcc_client_thread << Thread.new(ip, port, @uin, uin, code, filename, filesize, offset, callback) do |ip, port, client_uin, server_uin, code, filename, filesize, offset, callback|
|
217
|
-
begin
|
218
|
-
client = DCCClient.new(ip, port, client_uin, server_uin, code)
|
219
|
-
@dcc_client << client
|
220
|
-
if callback
|
221
|
-
client.client_send7(filename, filesize, offset) {|pos| callback.call(pos) }
|
222
|
-
else
|
223
|
-
client.client_send7(filename, filesize, offset)
|
224
|
-
end
|
225
|
-
rescue
|
226
|
-
warn "Error: #{$!}"
|
227
|
-
end
|
212
|
+
raise "dcc_request: no DCC server" unless @dcc
|
213
|
+
raise "dcc_request: file #{filename} not found" unless File.exist?(filename)
|
214
|
+
raise "dcc_request: #{uin} is not on the contact list" unless contact?(uin)
|
215
|
+
warn "dcc_request: optional parameter 'hash' is ignored and will be removed" if hash
|
216
|
+
return nil if get_status(uin) == :notavail
|
217
|
+
if version = get_version(uin) and version.to_f >= 7.6
|
218
|
+
write(0x23, 'L', 0x04)
|
219
|
+
sleep 0.1 until code = @dcc_code.shift
|
220
|
+
filesize=File.size(filename)
|
221
|
+
hash = filehash(filename, version)
|
222
|
+
write(0x20, 'a8LLLa226a29LLa20', code, @uin, uin, 0x04, File.basename(filename), '', filesize, 0, hash)
|
223
|
+
@dcc_action[code] = lambda do |offset|
|
224
|
+
if offset == -1
|
225
|
+
callback.call(:rejected) if callback
|
226
|
+
else
|
227
|
+
@dcc.add_send_code(code, filename, filesize, offset, &callback)
|
228
|
+
write(0x1f, 'LLa8a21a43', uin, 0x01, code, @socket.addr[3]+' '+@dccport.to_s, '')
|
229
|
+
if @socket.addr[3] =~ /^(10\.|172\.16\.|192\.168\.)/
|
230
|
+
@dcc_client_action[code] = lambda do |ip, port|
|
231
|
+
@dcc_client_thread << Thread.new(ip, port, @uin, uin, code, filename, filesize, offset, callback) do |ip, port, client_uin, server_uin, code, filename, filesize, offset, callback|
|
232
|
+
begin
|
233
|
+
client = DCCClient.new(ip, port, client_uin, server_uin, code)
|
234
|
+
@dcc_client << client
|
235
|
+
client.client_send7(filename, filesize, offset, &callback)
|
236
|
+
rescue
|
237
|
+
warn "Error: #{$!}"
|
228
238
|
end
|
229
239
|
end
|
230
240
|
end
|
231
241
|
end
|
232
242
|
end
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
rescue
|
246
|
-
warn "Error: #{$!}"
|
247
|
-
end
|
248
|
-
end
|
249
|
-
else
|
250
|
-
if callback
|
251
|
-
@dcc.add_send(uin, filename) {|pos| callback.call(pos) }
|
252
|
-
else
|
253
|
-
@dcc.add_send(uin, filename)
|
243
|
+
end
|
244
|
+
code
|
245
|
+
else
|
246
|
+
return nil if get_port(uin) == 2 or get_port(uin) == 0
|
247
|
+
if @socket.addr[3] =~ /^(10\.|172\.16\.|192\.168\.)/ and ip = get_ip(uin) and port = get_port(uin) and port > 2
|
248
|
+
@dcc_client_thread << Thread.new(ip, port, @uin, uin, filename, callback) do |ip, port, client_uin, server_uin, filename, callback|
|
249
|
+
begin
|
250
|
+
client = DCCClient.new(ip, port, client_uin, server_uin)
|
251
|
+
@dcc_client << client
|
252
|
+
client.client_send(filename, &callback)
|
253
|
+
rescue
|
254
|
+
warn "Error: #{$!}"
|
254
255
|
end
|
255
|
-
write(0x0b, 'LLLa*C', uin, rand(2**32), 0x10, "\x02", 0)
|
256
256
|
end
|
257
|
-
|
257
|
+
else
|
258
|
+
@dcc.add_send(uin, filename, &callback)
|
259
|
+
write(0x0b, 'LLLa*C', uin, rand(2**32), 0x10, "\x02", 0)
|
258
260
|
end
|
261
|
+
uin
|
259
262
|
end
|
260
263
|
end
|
261
264
|
|
@@ -279,12 +282,13 @@ Ustawia blok kodu jako zdarzenie wywolywane, gdy ktos zechce wyslac do nas plik.
|
|
279
282
|
def on_dcc_recv(&action)
|
280
283
|
raise "No DCC server" unless @dcc
|
281
284
|
@dcc_recv_action = action
|
282
|
-
@dcc.on_recv
|
285
|
+
@dcc.on_recv(&action)
|
283
286
|
@action[0x20] = lambda do |code, sender_uin, recv_uin, type, filename, x, filesize, y, hash|
|
284
287
|
if type==0x04
|
285
288
|
filename.sub!(/\x00.*/m, '')
|
289
|
+
filename.sub!(%r{.*/}, '')
|
286
290
|
if local_filename=action.call(sender_uin, filename, filesize)
|
287
|
-
if local_filename.
|
291
|
+
if local_filename.respond_to?(:to_ary)
|
288
292
|
local_filename, callback = local_filename
|
289
293
|
end
|
290
294
|
if File.exist?(local_filename)
|
@@ -292,11 +296,7 @@ Ustawia blok kodu jako zdarzenie wywolywane, gdy ktos zechce wyslac do nas plik.
|
|
292
296
|
else
|
293
297
|
offset = 0
|
294
298
|
end
|
295
|
-
|
296
|
-
@dcc.add_recv_code(code, local_filename, filesize, offset) {|pos| callback.call(pos) }
|
297
|
-
else
|
298
|
-
@dcc.add_recv_code(code, local_filename, filesize, offset)
|
299
|
-
end
|
299
|
+
@dcc.add_recv_code(code, local_filename, filesize, offset, &callback)
|
300
300
|
write(0x21, 'La8LL', sender_uin, code, offset, 0)
|
301
301
|
write(0x1f, 'LLa8a21a43', sender_uin, 0x01, code, @socket.addr[3]+' '+@dccport.to_s, '')
|
302
302
|
@dcc_client_action[code] = lambda do |ip, port|
|
@@ -304,11 +304,7 @@ Ustawia blok kodu jako zdarzenie wywolywane, gdy ktos zechce wyslac do nas plik.
|
|
304
304
|
begin
|
305
305
|
client = DCCClient.new(ip, port, client_uin, server_uin, code)
|
306
306
|
@dcc_client << client
|
307
|
-
|
308
|
-
client.client_recv7(filename, filesize, offset) {|pos| callback.call(pos) }
|
309
|
-
else
|
310
|
-
client.client_recv7(filename, filesize, offset)
|
311
|
-
end
|
307
|
+
client.client_recv7(filename, filesize, offset, &callback)
|
312
308
|
rescue
|
313
309
|
warn "Error: #{$!}"
|
314
310
|
end
|
@@ -321,39 +317,46 @@ Ustawia blok kodu jako zdarzenie wywolywane, gdy ktos zechce wyslac do nas plik.
|
|
321
317
|
end
|
322
318
|
end
|
323
319
|
|
320
|
+
=begin rdoc
|
321
|
+
Sprawdza czy *uin* jest na liscie kontaktow. Zwraca true lub false.
|
322
|
+
=end
|
323
|
+
def contact?(uin)
|
324
|
+
@status[uin] ? true : false
|
325
|
+
end
|
326
|
+
|
324
327
|
=begin rdoc
|
325
328
|
Zwraca status *uin* jesli jest on na liscie kontaktow. Status moze byc jednym z symboli: :avail, :busy, :notavail.
|
326
329
|
=end
|
327
330
|
def get_status(uin)
|
328
|
-
@status[uin][:status]
|
331
|
+
@status[uin][:status] if @status[uin]
|
329
332
|
end
|
330
333
|
|
331
334
|
=begin rdoc
|
332
335
|
Zwraca opis *uin* jesli jest on na liscie kontaktow.
|
333
336
|
=end
|
334
337
|
def get_description(uin)
|
335
|
-
@status[uin][:description]
|
338
|
+
@status[uin][:description] if @status[uin]
|
336
339
|
end
|
337
340
|
|
338
341
|
=begin rdoc
|
339
342
|
Zwraca adres IP *uin* jako lancuch znakow w postaci 4 liczb oddzielonych kropkami.
|
340
343
|
=end
|
341
344
|
def get_ip(uin)
|
342
|
-
@status[uin][:ip]
|
345
|
+
@status[uin][:ip] if @status[uin]
|
343
346
|
end
|
344
347
|
|
345
348
|
=begin rdoc
|
346
349
|
Zwraca port, na ktorym *uin* ma serwer DCC.
|
347
350
|
=end
|
348
351
|
def get_port(uin)
|
349
|
-
@status[uin][:port]
|
352
|
+
@status[uin][:port] if @status[uin]
|
350
353
|
end
|
351
354
|
|
352
355
|
=begin rdoc
|
353
356
|
Zwraca wersje klienta *uin* jako liczbe Float lub nil jesli nie rozpoznano wersji.
|
354
357
|
=end
|
355
358
|
def get_version(uin)
|
356
|
-
@status[uin][:version]
|
359
|
+
@status[uin][:version] if @status[uin]
|
357
360
|
end
|
358
361
|
|
359
362
|
=begin rdoc
|
@@ -380,6 +383,7 @@ Rozlacza sie z serwerem GG, wylacza serwer DCC i zamyka wszystkie polaczenia DCC
|
|
380
383
|
@socket.close
|
381
384
|
@dcc.close if @dcc
|
382
385
|
@dcc_client_thread.each {|t| t.exit }
|
386
|
+
nil
|
383
387
|
end
|
384
388
|
|
385
389
|
def write(type, pattern, *params)
|
@@ -419,6 +423,10 @@ Rozlacza sie z serwerem GG, wylacza serwer DCC i zamyka wszystkie polaczenia DCC
|
|
419
423
|
end
|
420
424
|
end
|
421
425
|
|
426
|
+
def set_action(type, &action)
|
427
|
+
@action[type] = action
|
428
|
+
end
|
429
|
+
|
422
430
|
def ping
|
423
431
|
write(0x08, '')
|
424
432
|
end
|
@@ -441,6 +449,29 @@ Rozlacza sie z serwerem GG, wylacza serwer DCC i zamyka wszystkie polaczenia DCC
|
|
441
449
|
y
|
442
450
|
end
|
443
451
|
|
452
|
+
def filehash(filename, version=7.7)
|
453
|
+
digest = Digest::SHA1.new
|
454
|
+
File.open(filename) do |f|
|
455
|
+
if File.size(filename) <= 10*1024*1024
|
456
|
+
while chunk = f.read(1024*1024)
|
457
|
+
digest << chunk
|
458
|
+
end
|
459
|
+
else
|
460
|
+
if version.to_s == '7.6'
|
461
|
+
chunksize = 0xfe000
|
462
|
+
else
|
463
|
+
chunksize = 0x100000
|
464
|
+
end
|
465
|
+
seekjump = (File.size(filename)-0x100000)/9
|
466
|
+
9.times do |i|
|
467
|
+
f.seek i*seekjump
|
468
|
+
digest << f.read(chunksize)
|
469
|
+
end
|
470
|
+
end
|
471
|
+
end
|
472
|
+
digest.digest
|
473
|
+
end
|
474
|
+
|
444
475
|
def msg_received(sender, seq, time, cl, message)
|
445
476
|
if cl == 0x10 and message.chomp(0.chr) == 2.chr
|
446
477
|
if @dcc_recv_action and ip = get_ip(sender) and port = get_port(sender) and port > 1
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
|
|
3
3
|
specification_version: 1
|
4
4
|
name: rgadu
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2007-
|
6
|
+
version: 0.2.0
|
7
|
+
date: 2007-09-23 00:00:00 +02:00
|
8
8
|
summary: A simple pure-Ruby implementation of the Gadu-Gadu protocol.
|
9
9
|
require_paths:
|
10
10
|
- lib
|