xget 2.1.2 → 2.1.3

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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/bin/xget +5 -4
  3. metadata +10 -13
  4. data/xget.rb +0 -709
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 83fdd3d062e8a390cfcfa6ae370b0a8e60b13f0c
4
- data.tar.gz: 03e0bdbe3fe72a6218c267e23f523538273cd71c
3
+ metadata.gz: 8e89c9b60dfa10865cc36cb62f27ae2962ed4d4f
4
+ data.tar.gz: 0d95cecbf53321d7596441318d656c77155404e8
5
5
  SHA512:
6
- metadata.gz: 8ee5154095a6fca530c8d305ec6b2600d606e74338e483605232e93c5816754111b29a6c1c5cd56e4d983eda57237cee58e649c7a6a5b0e9bad18367399b2c9a
7
- data.tar.gz: d1d5ac5df98bb374e06b4383009c99ecf9913456898a061cf10c6e76efd4acd74eb2f6491f41daf9d2c305f7160f3e04263e9d589f1991a45b9f2ced8dc6e01a
6
+ metadata.gz: 62e521d6be909458af3a59228ede37666b1d977ca73778858415b9121643e5dca17bc5d77b578a93a6d7ec9abea04cc5bc12c3ceb4fc29d217d9ccf1fd67e1b4
7
+ data.tar.gz: 8ba338901c35b25c6d02dff44c860ccb159f563202610d9e2861a34ebed761b065aaf013c6a591595f9a474a858cef5d7fbf2ea874bdace0e173cdace280fe72
data/bin/xget CHANGED
@@ -6,10 +6,9 @@
6
6
  # All rights reserved.
7
7
 
8
8
  begin
9
- require 'Win32/Console/ANSI' if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
10
9
  %w(socket thread slop timeout).each { |r| require r }
11
10
  rescue LoadError
12
- abort "#{$0} requires slop and, if you're on Windows, win32console\nPlease run 'gem install slop win32console'"
11
+ abort "#{$0} Requires slop - Please run 'gem install slop'"
13
12
  end
14
13
 
15
14
  # Why isn't this enabled by default?
@@ -135,6 +134,7 @@ class Stream
135
134
 
136
135
  def disconnect
137
136
  @io.puts 'QUIT'
137
+ rescue Errno::EPIPE
138
138
  end
139
139
 
140
140
  def << data
@@ -182,6 +182,7 @@ class Bot
182
182
  def tick
183
183
  stream.read
184
184
  stream.write
185
+ sleep 0.001
185
186
  end
186
187
  end
187
188
 
@@ -433,7 +434,7 @@ config["allow-queueing"] = opts["allow-queueing"] if opts["allow-queueing"]
433
434
  config["sleep-interval"] = opts["sleep-interval"] unless opts["sleep-interval"].nil?
434
435
 
435
436
  # Take remaining arguments and all lines from --files arg and put into array
436
- to_check = ($*)
437
+ to_check = opts.arguments
437
438
  if opts['files'] != nil and not opts['files'].empty?
438
439
  opts['files'].each do |x|
439
440
  File.open(x, "r").each_line { |y| to_check << y.chomp } if File.exists? x
@@ -471,7 +472,7 @@ to_check.each do |x|
471
472
  end
472
473
  end
473
474
  else
474
- puts_abort "#{x} is not a valid XDCC address\n XDCC Address format: #chan@irc.serv.com/bot/pack(s)"
475
+ puts_abort "#{x} is not a valid XDCC address\n XDCC Address format: #chan@irc.serv.com/bot/pack(s) or ^\/msg irc.serv.com bot xdcc send #id$"
475
476
  end
476
477
  end
477
478
 
metadata CHANGED
@@ -1,27 +1,24 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xget
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.2
4
+ version: 2.1.3
5
5
  platform: ruby
6
6
  authors:
7
- - George Watson
7
+ - Rory B. Bellows
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-04-19 00:00:00.000000000 Z
11
+ date: 2010-04-03 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: XDCC Download Client
13
+ description: XDCC download client
14
14
  email: gigolo@hotmail.co.uk
15
- executables:
16
- - xget
15
+ executables: []
17
16
  extensions: []
18
17
  extra_rdoc_files: []
19
18
  files:
20
19
  - bin/xget
21
- - xget.rb
22
- homepage: http://rubygems.org/gems/hola
23
- licenses:
24
- - MIT
20
+ homepage: https://github.com/takeiteasy/xget
21
+ licenses: []
25
22
  metadata: {}
26
23
  post_install_message:
27
24
  rdoc_options: []
@@ -39,8 +36,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
39
36
  version: '0'
40
37
  requirements: []
41
38
  rubyforge_project:
42
- rubygems_version: 2.5.1
39
+ rubygems_version: 2.5.2
43
40
  signing_key:
44
- specification_version: 4
45
- summary: XDCC Download Client
41
+ specification_version: 3
42
+ summary: XDCC download client
46
43
  test_files: []
data/xget.rb DELETED
@@ -1,709 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- # xget.rb - xget
4
- # Created by Rusty Shackleford on 2013/05/19
5
- # Copyright (c) 2013, Rusty Shackleford
6
- # All rights reserved.
7
-
8
- begin
9
- require 'Win32/Console/ANSI' if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
10
- %w(socket thread slop timeout).each { |r| require r }
11
- rescue LoadError
12
- abort "#{$0} requires slop and, if you're on Windows, win32console\nPlease run 'gem install slop win32console'"
13
- end
14
-
15
- # Why isn't this enabled by default?
16
- Thread.abort_on_exception = true
17
- # Put standard output into syncronised mode
18
- $stdout.sync = true
19
-
20
- # Version values
21
- $ver_maj, $ver_min, $ver_rev = 2, 1, 1
22
- $ver_str = "#{$ver_maj}.#{$ver_min}.#{$ver_rev}"
23
-
24
- config = {
25
- "out-dir" => './',
26
- "skip-existing" => false,
27
- "servers" => {},
28
- "sleep-interval" => 5,
29
- "allow-queueing" => false
30
- }
31
-
32
- def puts_error msg
33
- puts "! \e[31mERROR\e[0m: #{msg}"
34
- end
35
-
36
- def puts_abort msg
37
- abort "! \e[31mERROR\e[0m: #{msg}"
38
- end
39
-
40
- def puts_warning msg
41
- puts "! \e[33mWARNING:\e[0m: #{msg}"
42
- end
43
-
44
- # Extend IO to readlines without blocking
45
- class IO
46
- def gets_nonblock
47
- @rlnb_buffer ||= ""
48
- ch = nil
49
- while ch = self.read_nonblock(1)
50
- @rlnb_buffer += ch
51
- if ch == "\n" then
52
- res = @rlnb_buffer
53
- @rlnb_buffer = ""
54
- return res
55
- end
56
- end
57
- end
58
- end
59
-
60
- # Extend Array to get averages
61
- class Array
62
- def average
63
- inject(:+) / count
64
- end
65
- end
66
-
67
- # Class to hold XDCC requests
68
- class XDCC_REQ
69
- attr_accessor :serv, :chan, :bot, :pack, :info
70
-
71
- def initialize serv, chan, bot, pack, info = "*"
72
- @serv = serv
73
- @chan = chan
74
- @bot = bot
75
- @pack = pack
76
- @info = info
77
- end
78
-
79
- def eql? other
80
- self.serv == other.serv and self.chan == other.chan and self.bot == other.bot and self.pack == other.pack
81
- end
82
-
83
- def to_s
84
- "[ #{self.serv}, #{self.chan}, #{self.bot}, #{self.pack}, #{self.info} ]"
85
- end
86
- end
87
-
88
- # Class to hold DCC SEND info for when waiting for DCC ACCEPT
89
- class XDCC_SEND
90
- attr_accessor :fname, :fsize, :ip, :port
91
-
92
- def initialize fname, fsize, ip, port
93
- @fname = fname
94
- @fsize = fsize
95
- @ip = ip
96
- @port = port
97
- end
98
-
99
- def to_s
100
- "[ #{self.fname}, #{self.fsize}, #{self.ip}, #{self.port} ]"
101
- end
102
- end
103
-
104
- # Class to emit events
105
- module Emitter
106
- def callbacks
107
- @callbacks ||= Hash.new { |h, k| h[k] = [] }
108
- end
109
-
110
- def on type, &block
111
- callbacks[type] << block
112
- self
113
- end
114
-
115
- def emit type, *args
116
- callbacks[type].each do |block|
117
- block.call(*args)
118
- end
119
- end
120
- end
121
-
122
- # Class to handle IRC stream and emit events
123
- class Stream
124
- include Emitter
125
- attr_accessor :io, :buf
126
-
127
- def initialize serv
128
- @buf = []
129
- Timeout.timeout(5) { @io = TCPSocket.new serv, 6667 }
130
- rescue SocketError => e
131
- puts_abort "Failed to connect to #{serv}! #{e.message}"
132
- rescue Timeout::Error
133
- puts_abort "Connection to #{serv} timed out!"
134
- end
135
-
136
- def disconnect
137
- @io.puts 'QUIT'
138
- end
139
-
140
- def << data
141
- @buf << data
142
- end
143
-
144
- def write
145
- @buf.each do |x|
146
- @io.puts x
147
- emit :WROTE, x
148
- end
149
- @buf = []
150
- rescue EOFError, Errno::ECONNRESET
151
- emit :CLOSED
152
- end
153
-
154
- def read
155
- read = @io.gets_nonblock
156
- emit :READ, read
157
- rescue IO::WaitReadable
158
- emit :WAITING
159
- rescue EOFError, Errno::ECONNRESET
160
- emit :CLOSED
161
- end
162
- end
163
-
164
- # Class to handle IRC stream
165
- class Bot
166
- attr_reader :stream
167
-
168
- def initialize stream
169
- @stream = stream
170
- stream.on :CLOSED do stop; end
171
- end
172
-
173
- def start
174
- @running = true
175
- tick while @running
176
- end
177
-
178
- def stop
179
- @running = false
180
- end
181
-
182
- def tick
183
- stream.read
184
- stream.write
185
- end
186
- end
187
-
188
- # Get relative size from bytes
189
- def bytes_to_closest bytes
190
- fsize_arr = [ 'B', 'KB', 'MB', 'GB', 'TB' ]
191
- exp = (Math.log(bytes) / Math.log(1024)).to_i
192
- exp = fsize_arr.length if exp > fsize_arr.length
193
- bytes /= 1024.0 ** exp
194
- return "#{bytes.round(2)}#{fsize_arr[exp]}"
195
- end
196
-
197
- # Loop until there is no file with the same name
198
- def safe_fname fname
199
- return fname unless File.exists? fname
200
-
201
- ext = File.extname fname
202
- base = File.basename fname, ext
203
- dir = File.dirname fname
204
-
205
- cur = 2
206
- while true
207
- test = "#{dir}/#{base} (#{cur})#{ext}"
208
- return test unless File.exists? test
209
- cur += 1
210
- end
211
- end
212
-
213
- # Get a close relative time remaining, in words
214
- def time_distance t
215
- if t < 60
216
- case t
217
- when 0 then "- nevermind, done!"
218
- when 1..4 then "in a moment!"
219
- when 5..9 then "less than 10 seconds"
220
- when 10..19 then "less than 20 seconds"
221
- when 20..39 then "half a minute"
222
- else "less than a minute"
223
- end
224
- else # Use minutes, to aovid big numbers
225
- t = t / 60.0
226
- case t.to_i
227
- when 1 then "about a minute"
228
- when 2..45 then "#{t.round} minutes"
229
- when 45..90 then "about an hour"
230
- when 91..1440 then "about #{(t / 60.0).round} hours"
231
- when 1441..2520 then "about a day"
232
- when 2521..86400 then "about #{(t / 1440.0).round} days"
233
- else "about #{(t/ 43200.0).round} months"
234
- end
235
- end
236
- end
237
-
238
- # Get elapsed time in words
239
- def time_elapsed t
240
- return "instantly!" if t <= 0
241
-
242
- # Get the GMTime from seconds and split
243
- ta = Time.at(t).gmtime.strftime('%S|%M|%H|%-d|%-m|%Y').split('|', 6).collect { |i| i.to_i }
244
- ta[-1] -= 1970 # fuck the police
245
- ta[-2] -= 1 # fuck, fuck
246
- ta[-3] -= 1 # fuck the police
247
-
248
- # Remove the 0 digets
249
- i = 0
250
- ta.reverse.each do |x|
251
- break if x != 0
252
- i += 1
253
- end
254
-
255
- # Unit suffixes
256
- suffix = [ "seconds", "minutes", "hours", "days", "months", "years" ]
257
- # Don't use plural if x is 1
258
- plural = ->(x, y) { x == 1 ? y[0..-2] : y }
259
- # Format string to "value unit"
260
- format_str = ->(x) { "#{ta[x]} #{plural[ta[x], suffix[x]]}, " }
261
-
262
- # Form the string
263
- ta = ta.take(ta.length - i)
264
- str = ""
265
- (ta.length - 1).downto(0) { |x| str += format_str[x] }
266
- "in #{str[0..-3]}"
267
- end
268
-
269
- # DCC download handler
270
- def dcc_download ip, port, fname, fsize, read = 0
271
- sock = nil
272
- begin
273
- Timeout.timeout(5) { sock = TCPSocket.new ip, port }
274
- rescue Timeout::Error
275
- puts_abort "Connection to #{ip} timed out!"
276
- end
277
- puts_abort "Failed to connect to \"#{ip}:#{port}\": #{e}" if sock.nil?
278
-
279
- fsize_clean = bytes_to_closest fsize
280
- avgs, last_check, start_time = [], Time.now - 2, Time.now
281
- fh = File.open fname, (read == 0 ? "w" : "a") # Write or append
282
-
283
- # Form the status bar
284
- print_bar = ->() {
285
- print "\r\e[0K> [ \e[1;37m"
286
- pc = read.to_f / fsize.to_f * 100.0
287
- bars = (pc / 10).to_i
288
- bars.times { print "#" }
289
- (10 - bars).times { print " " }
290
- avg = avgs.average * 1024.0
291
- time_rem = time_distance ((fsize - read) / avg) * 8.0
292
- print "\e[0m ] #{pc.round(2)}% #{bytes_to_closest read}/#{fsize_clean} \e[1;37m@\e[0m #{bytes_to_closest avg}/s \e[1;37min\e[0m #{time_rem}"
293
-
294
- last_check = Time.now
295
- avgs.clear
296
- }
297
-
298
- while buf = sock.readpartial(8192)
299
- read += buf.bytesize
300
- avgs << buf.bytesize
301
- print_bar[] if (Time.now - last_check) > 1 and not avgs.empty?
302
-
303
- begin
304
- sock.write_nonblock [read].pack('N')
305
- rescue Errno::EWOULDBLOCK
306
- rescue Errno::EAGAIN => e
307
- puts_error "#{File.basename fname} timed out! #{e}"
308
- end
309
-
310
- fh << buf
311
- break if read >= fsize
312
- end
313
- print_bar.call unless avgs.empty?
314
- elapsed_time = time_elapsed (Time.now - start_time).to_i
315
-
316
- sock.close
317
- fh.close
318
-
319
- puts "\n! \e[1;32mSUCCESS\e[0m: downloaded #{File.basename fname} #{elapsed_time}"
320
- rescue EOFError, SocketError => e
321
- puts "\n! ERROR: #{File.basename fname} failed to download! #{e}"
322
- end
323
-
324
- opts = Slop.parse do |o|
325
- o.banner = " Usage: #{$0} [options] [value] [links] [--files] [file1:file2:file3]\n"
326
- o.bool '-h', '--help', 'Prints help'
327
-
328
- o.on '-v', '--version', 'Print version' do
329
- puts "#{$0}: v#{$ver_str}"
330
- exit
331
- end
332
-
333
- o.string '--config', 'Config file location'
334
- o.string '--user', 'IRC \'USER\' for Ident'
335
- o.string '--nick', 'IRC nick'
336
- o.string '--pass', 'IRC \'PASS\' for Ident'
337
- o.string '--realname', 'Realname for \'USER\' Ident'
338
- o.string '--nickserv', 'Password for Nickserv'
339
- o.array '--files', 'Pass list of files to parse for links', as: Array, delimiter: ':'
340
- o.string '--out-dir', 'Output directory to save fiels to', :default => "./"
341
- o.bool '--skip-existing', 'Don\' download files that already exist'
342
- o.bool '--allow-queueing', 'Wait for pack to start downloading rather than fail immediately when queued'
343
- o.int '--sleep-interval', 'Time in seconds to sleep before requesting next pack. Zero for no sleep.'
344
- end
345
-
346
- if opts.help?
347
- puts opts
348
- puts "\n Examples"
349
- puts " \txget.rb --config config.conf --nick test"
350
- puts " \txget.rb --files test1.txt:test2.txt:test3.txt"
351
- puts " \txget.rb #news@irc.rizon.net/ginpachi-sensei/1"
352
- puts " \txget.rb #news@irc.rizon.net/ginpachi-sensei/41..46"
353
- puts " \txget.rb #news@irc.rizon.net/ginpachi-sensei/41..46|2"
354
- puts " \txget.rb #news@irc.rizon.net/ginpachi-sensei/41..46&49..52|2&30"
355
- exit
356
- end
357
-
358
- # Get the config location
359
- config_loc = opts["config"]
360
- config_loc = File.expand_path config_loc unless config_loc.nil?
361
- if config_loc.nil? or not File.exists? config_loc
362
- config_loc = File.expand_path "~/.xget.conf"
363
- config_loc = ".xget.conf" unless File.exists? config_loc
364
-
365
- unless File.exists? config_loc
366
- puts "ERROR! Invalid config path '#{config_loc}''. Exiting!"
367
- exit
368
- end
369
- end
370
-
371
- # Insert config settings from arguments into config hash
372
- cur_block = "*"
373
- config["servers"][cur_block] = {}
374
- %w(user nick pass real nserv).each do |x|
375
- config["servers"][cur_block][x.to_sym] = opts[x] unless opts[x].nil?
376
- end
377
-
378
- # Check if specified output directory actually exists
379
- puts_abort "Out directory, \"#{opts["out-dir"]}\" doesn't exist!" unless Dir.exists? opts["out-dir"]
380
- config["out-dir"] = opts["out-dir"].dup
381
- config["out-dir"] << "/" unless config["out-dir"][-1] == "/"
382
-
383
- # Parse config
384
- config_copies = {}
385
- File.open(config_loc, "r").each_line do |line|
386
- next if line.length <= 1 or line[0] == '#'
387
-
388
- if line =~ /^\[(\S+)\]$/ # Check if header
389
- cur_block = $1
390
- if cur_block.include? ',' # Check if header contains more than one server
391
- tmp_split = cur_block.split(",")
392
- next unless tmp_split[0] =~ /^(\w+?).(\w+?).(\w+?)$/
393
- config_copies[tmp_split[0]] = []
394
- tmp_split.each do |x| # Add all copies to copies hash
395
- next if x == tmp_split[0] or not x =~ /^(\w+?).(\w+?).(\w+?)$/
396
- config_copies[tmp_split[0]].push x unless config_copies[tmp_split[0]].include? x
397
- end
398
- cur_block = tmp_split[0]
399
- end
400
-
401
- # Set current block to the new header
402
- config["servers"][cur_block] = {} unless config["servers"].has_key? cur_block
403
- elsif line =~ /^(\S+)=(.*+?)$/
404
- # Check if current line is specifying out directory
405
- case $1
406
- when "out-dir"
407
- t_out_dir = File.expand_path $2
408
- puts_abort "Out directory, \"#{t_out_dir}\" doesn't exist!" unless Dir.exists? t_out_dir
409
- config[$1] = t_out_dir
410
- config[$1] << "/" unless config[$1][-1] == "/"
411
- next
412
- when "sleep-interval" then config[$1] = $2.to_i
413
- when "skip-existing" then config[$1] = ($2 == "true")
414
- when "allow-queueing" then config[$1] = ($2 == "true")
415
- else
416
- # Add value to current header, default is *
417
- t_sym = $1.downcase.to_sym
418
- config["servers"][cur_block][t_sym] = $2 unless config["servers"][cur_block].has_key? t_sym
419
- end
420
- end
421
- end
422
-
423
- # Go through each and make copies of the original
424
- unless config_copies.empty?
425
- config_copies.each do |k,v|
426
- v.each { |x| config["servers"][x] = config["servers"][k] }
427
- end
428
- end
429
-
430
- # Set the set the command line config options if specified
431
- config["skip-existing"] = opts["skip-existing"] if opts["skip-existing"]
432
- config["allow-queueing"] = opts["allow-queueing"] if opts["allow-queueing"]
433
- config["sleep-interval"] = opts["sleep-interval"] unless opts["sleep-interval"].nil?
434
-
435
- # Take remaining arguments and all lines from --files arg and put into array
436
- to_check = ($*)
437
- if opts['files'] != nil and not opts['files'].empty?
438
- opts['files'].each do |x|
439
- File.open(x, "r").each_line { |y| to_check << y.chomp } if File.exists? x
440
- end
441
- end
442
-
443
- if to_check.empty?
444
- puts opts
445
- abort "\n No jobs, nothing to do!"
446
- end
447
-
448
- # Parse to_check array for valid XDCC links, irc.serv.org/#chan/bot/pack
449
- tmp_requests = []
450
- to_check.each do |x|
451
- if x =~ /^(#\S+)@(irc.\w+.\w+{2,3})\/(\S+)\/([\.&\|\d]+)$/
452
- chan = $1
453
- serv = $2
454
- bot = $3
455
- info = config["servers"].has_key?(serv) ? serv : "*"
456
- $4.split('&').each do |y|
457
- if y =~ /^(\d+)(\.\.\d+(\|\d+)?)?$/
458
- pack = $1.to_i
459
- if $2.nil?
460
- tmp_requests.push XDCC_REQ.new serv, chan, bot, pack, info
461
- else
462
- step = $3.nil? ? 1 : $3[1..-1].to_i
463
- range = $2[2..-1].to_i
464
-
465
- puts_abort "Invalid range #{pack} to #{range} in \"#{x}\"" if pack > range or pack == range
466
-
467
- (pack..range).step(step).each do |z|
468
- tmp_requests.push XDCC_REQ.new serv, chan, bot, z, info
469
- end
470
- end
471
- end
472
- end
473
- else
474
- puts_abort "#{x} is not a valid XDCC address\n XDCC Address format: #chan@irc.serv.com/bot/pack(s)"
475
- end
476
- end
477
-
478
- # Remove duplicate entries from requests
479
- i = j = 0
480
- to_pop = []
481
- tmp_requests.each do |x|
482
- tmp_requests.each do |y|
483
- to_pop << j if x.eql? y if i != j
484
- j += 1
485
- end
486
- i += 1
487
- end
488
- to_pop.each { |x| tmp_requests.delete_at(x) }
489
-
490
- # Sort requests array to hash, serv {} -> chan {} -> requests []
491
- requests = {}
492
- tmp_requests.each do |x|
493
- requests[x.serv] = [] unless requests.has_key? x.serv
494
- requests[x.serv] << x
495
- end
496
-
497
- if requests.empty?
498
- puts opts
499
- abort "\n No jobs, nothing to do!"
500
- end
501
-
502
- # Sort requests by pack
503
- requests.each do |k,v|
504
- puts "#{k} \e[1;37m->\e[0m"
505
- v.sort_by { |x| [x.chan, x.bot, x.pack] }.each { |x| puts " #{x}" }
506
- end
507
- puts
508
-
509
- # H-h-here we g-go...
510
- requests.each do |k, v|
511
- req, info = v[0], config["servers"][v[0].info]
512
- last_chan, cur_req, motd = "", -1, false
513
- nick_sent, nick_check, nick_valid = false, false, false
514
- xdcc_sent, xdcc_accepted, xdcc_queued = false, false, false
515
- xdcc_accept_time, xdcc_ret, req_send_time = nil, nil, nil
516
-
517
- stream = Stream.new req.serv
518
- bot = Bot.new stream
519
- stream << "NICK #{info[:nick]}"
520
- stream << "USER #{info[:user]} 0 * #{info[:real]}"
521
- stream << "PASS #{info[:pass]}" unless info[:pass].nil?
522
-
523
- # Handle read data
524
- stream.on :READ do |data|
525
- /^(?:[:](?<prefix>\S+) )?(?<type>\S+)(?: (?!:)(?<dest>.+?))?(?: [:](?<msg>.+))?$/ =~ data
526
- #puts "\e[1;37m>>\e[0m #{prefix} | #{type} | #{dest} | #{msg}"
527
-
528
- case type
529
- when 'NOTICE'
530
- if dest == 'AUTH'
531
- if msg =~ /erroneous nickname/i
532
- puts_error 'Login failed'
533
- stream.disconnect
534
- end
535
- #puts "> \e[1;32m#{msg}\e[0m"
536
- else
537
- if prefix =~ /^NickServ!/
538
- if not nick_sent and info[:nserv] != nil
539
- stream << "PRIVMSG NickServ :IDENTIFY #{info[:nserv]}"
540
- nick_sent = true
541
- elsif nick_sent and not nick_check
542
- case msg
543
- when /password incorrect/i
544
- nick_valid = false
545
- nick_check = true
546
- when /password accepted/i
547
- nick_valid = true
548
- nick_check = true
549
- end
550
- end
551
- #puts "> \e[1;33m#{msg}\e[0m"
552
- elsif prefix =~ /^#{Regexp.escape req.bot}!(.*)$/i
553
- case msg
554
- when /already requested that pack/i, /closing connection/i, /you have a dcc pending/i
555
- puts_error msg
556
- stream << "PRIVMSG #{req.bot} :XDCC CANCEL"
557
- stream << 'QUIT'
558
- when /you can only have (\d+?) transfer at a time/i
559
- if config["allow-queueing"]
560
- puts "! #{prefix}: #{msg}"
561
- puts_warning "Pack queued, waiting for transfer to start..."
562
- xdcc_queued = true
563
- else
564
- puts_error msg
565
- stream << "PRIVMSG #{req.bot} :XDCC CANCEL"
566
- stream << 'QUIT'
567
- end
568
- else
569
- puts "! #{prefix}: #{msg}"
570
- end
571
- end
572
- end
573
- when 'PRIVMSG'
574
- if xdcc_sent and not xdcc_accepted and prefix =~ /#{Regexp.escape req.bot}!(.*)$/i
575
- /^\001DCC SEND (?<fname>((".*?").*?|(\S+))) (?<ip>\d+) (?<port>\d+) (?<fsize>\d+)\001\015$/ =~ msg
576
- unless $~.nil?
577
- req_send_time = nil
578
-
579
- tmp_fname = fname
580
- fname = $1 if tmp_fname =~ /^"(.*)"$/
581
- puts "Preparing to download: \e[36m#{fname}\e[0m"
582
- fname = (config["out-dir"].dup << fname)
583
- xdcc_ret = XDCC_SEND.new fname, fsize.to_i, [ip.to_i].pack('N').unpack('C4') * '.', port.to_i
584
-
585
- # Check if the for unfinished download amd try to resume
586
- if File.exists? xdcc_ret.fname and File.stat(xdcc_ret.fname).size < xdcc_ret.fsize
587
- stream << "PRIVMSG #{req.bot} :\001DCC RESUME #{tmp_fname} #{xdcc_ret.port} #{File.stat(xdcc_ret.fname).size}\001"
588
- xdcc_accepted = true
589
- print "! Incomplete file detected. Attempting to resume..."
590
- next # Skip and wait for "DCC ACCEPT"
591
- elsif File.exists? xdcc_ret.fname
592
- if config["skip-existing"]
593
- puts_warning "File already exists, skipping..."
594
- stream << "PRIVMSG #{req.bot} :XDCC CANCEL"
595
-
596
- xdcc_sent, xdcc_accepted, xdcc_queued = false, false, false
597
- xdcc_accept_time, xdcc_ret = nil, nil
598
- next
599
- else
600
- puts_warnings "File already existing, using a safe name..."
601
- xdcc_ret.fname = safe_fname xdcc_ret.fname
602
- end
603
- end
604
-
605
- # It's a new download, start from beginning
606
- Thread.new do
607
- pid = fork do
608
- puts "Connecting to: #{req.bot} @ #{xdcc_ret.ip}:#{xdcc_ret.port}"
609
- dcc_download xdcc_ret.ip, xdcc_ret.port, xdcc_ret.fname, xdcc_ret.fsize
610
- end
611
-
612
- Process.wait pid
613
- xdcc_sent, xdcc_accepted, xdcc_queued = false, false, false
614
- xdcc_accept_time, xdcc_ret = nil, nil
615
- end
616
- end
617
- elsif xdcc_accepted and xdcc_ret != nil and msg =~ /^\001DCC ACCEPT ((".*?").*?|(\S+)) (\d+) (\d+)\001\015$/
618
- # DCC RESUME request accepted, continue the download!
619
- xdcc_accept_time = nil
620
- xdcc_accepted = false
621
- puts "\e[1;32mSUCCESS\e[0m!"
622
-
623
- Thread.new do
624
- pid = fork do
625
- puts "Connecting to: #{req.bot} @ #{xdcc_ret.ip}:#{xdcc_ret.port}"
626
- dcc_download xdcc_ret.ip, xdcc_ret.port, xdcc_ret.fname, xdcc_ret.fsize, File.stat(xdcc_ret.fname).size
627
- end
628
-
629
- Process.wait pid
630
- xdcc_sent, xdcc_accepted, xdcc_queued = false, false, false
631
- xdcc_accept_time, xdcc_ret = nil, nil
632
- end
633
- end
634
- when /^\d+?$/
635
- type_i = type.to_i
636
- case type_i
637
- # when 1 # Print welcome message, because it's nice
638
- # msg.sub!(/#{Regexp.escape info[:nick]}/, "\e[34m#{info[:nick]}\e[0m")
639
- # puts "! #{msg}"
640
- when 400..533 # Handle errors, except a few
641
- next if [439, 462, 477].include? type_i
642
- puts_error "#{msg}"
643
- stream.disconnect
644
- when 376 then motd = true # Mark the end of the MOTD
645
- end
646
- when 'PING' then stream << "PONG :#{msg}"
647
- when 'ERROR' then (msg =~ /closing link/i ? puts(msg) : puts_error(msg))
648
- end
649
- end
650
-
651
- # Handle things while waiting for data
652
- stream.on :WAITING do
653
- unless xdcc_accepted
654
- if motd and not xdcc_sent
655
- cur_req += 1
656
- if cur_req >= v.length
657
- stream.disconnect
658
- next
659
- end
660
- req = v[cur_req]
661
-
662
- if req.chan != last_chan
663
- stream << "PART #{last_chan}" unless last_chan == ""
664
- last_chan = req.chan
665
- stream << "JOIN #{req.chan}"
666
- end
667
-
668
- # Cooldown between downloads
669
- if cur_req > 0
670
- puts "Sleeping for #{config["sleep-interval"]} seconds before requesting the next pack"
671
- sleep(config["sleep-interval"])
672
- end
673
-
674
- stream << "PRIVMSG #{req.bot} :XDCC SEND #{req.pack}"
675
- req_send_time = Time.now
676
- xdcc_sent = true
677
- end
678
-
679
- # Wait 3 seconds for DCC SEND response, if there isn't one, abort
680
- if xdcc_sent and not req_send_time.nil? and not xdcc_accepted
681
- if config["allow-queueing"] and xdcc_queued
682
- next
683
- end
684
- if (Time.now - req_send_time).floor > 10
685
- puts_error "#{req.bot} took too long to respond, are you sure it's a bot?"
686
- stream.disconnect
687
- bot.stop
688
- end
689
- end
690
-
691
- # Wait 3 seconds for a DCC ACCEPT response, if there isn't one, don't resume
692
- if xdcc_sent and xdcc_accepted and not xdcc_accept_time.nil?
693
- if (Time.now - xdcc_accept_time).floor > 10
694
- puts "FAILED! Bot client doesn't support resume!"
695
- puts "Connecting to: #{req.bot} @ #{xdcc_ret.ip}:#{xdcc_ret.port}"
696
- dcc_download xdcc_ret.ip, xdcc_ret.port, xdcc_ret.fname, xdcc_ret.fsize
697
- end
698
- end
699
- end
700
- end
701
-
702
- # Print sent data, for debugging only really
703
- stream.on :WROTE do |data|
704
- #puts "\e[1;37m<<\e[0m #{data}"
705
- end
706
-
707
- # Start the bot
708
- bot.start
709
- end