fargo 0.2.0 → 0.3.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/README.md ADDED
@@ -0,0 +1,61 @@
1
+ # Fargo
2
+
3
+ This gem is an implementation of the [Direct Connect (DC) protocol](http://en.wikipedia.org/wiki/Direct_Connect_\(file_sharing\)) in ruby.
4
+
5
+ ## Installation
6
+
7
+ `gem install fargo`
8
+
9
+ ## Usage
10
+
11
+ <pre>
12
+ require 'fargo'
13
+
14
+ client = Fargo::Client.new
15
+
16
+ client.configure do |config|
17
+ config.hub_address = [address of the hub] # Defaults to 127.0.0.1
18
+ config.hub_port = [port of the hub] # Defaults to 7314
19
+ config.passive = true # Defaults to false
20
+ config.address = '1.2.3.4' # Defaults to machine IP
21
+ config.active_port = [port to listen on] # Defaults to 7315
22
+ config.search_port = [port to listen on] # Defaults to 7316
23
+ end
24
+
25
+ EventMachine.run {
26
+ client.connect
27
+
28
+ client.nicks # list of nicks registered
29
+ client.download nick, file # download a file from a user
30
+ client.file_list nick # get a list of files from a user
31
+
32
+ client.channel.subscribe do |type, message|
33
+ # type is the type of message
34
+ # message is a hash of what was received
35
+ end
36
+ }
37
+ </pre>
38
+
39
+ See `lib/fargo/client.rb` for a full list of configuration options
40
+
41
+ ## MIT License
42
+
43
+ Copyright (c) 2010 Alex Crichton
44
+
45
+ Permission is hereby granted, free of charge, to any person obtaining a copy
46
+ of this software and associated documentation files (the "Software"), to deal
47
+ in the Software without restriction, including without limitation the rights
48
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
49
+ copies of the Software, and to permit persons to whom the Software is
50
+ furnished to do so, subject to the following conditions:
51
+
52
+ The above copyright notice and this permission notice shall be included in
53
+ all copies or substantial portions of the Software.
54
+
55
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
56
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
57
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
58
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
59
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
60
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
61
+ THE SOFTWARE.
data/ext/fargo/extconf.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # This uses mkmf
2
2
  require 'mkmf'
3
3
 
4
- if RUBY_VERSION =~ /1.9/
4
+ if RUBY_VERSION =~ /1\.9/
5
5
  $CFLAGS << ' -DRUBY_19'
6
6
  end
7
7
 
@@ -5,8 +5,6 @@
5
5
  #ifndef RUBY_19
6
6
  # define RSTRING_LEN(s) (RSTRING(s)->len)
7
7
  # define RSTRING_PTR(s) (RSTRING(s)->ptr)
8
- # define RARRAY_LEN(s) (RARRAY(s)->len)
9
- # define RARRAY_PTR(s) (RARRAY(s)->ptr)
10
8
  #endif
11
9
 
12
10
  VALUE rb_tth_file(VALUE self, VALUE filename) {
data/lib/fargo/client.rb CHANGED
@@ -8,19 +8,21 @@ module Fargo
8
8
  include ActiveSupport::Configurable
9
9
  include ActiveSupport::Callbacks
10
10
 
11
- define_callbacks :initialization
12
-
13
- include Fargo::Supports::Chat
14
- include Fargo::Supports::Uploads
15
- include Fargo::Supports::NickList
16
- include Fargo::Supports::Searches
17
- include Fargo::Supports::Downloads
18
- include Fargo::Supports::Persistence
19
- include Fargo::Supports::Timeout
20
- include Fargo::Supports::FileList
11
+ define_callbacks :initialization, :connect
12
+
13
+ include Supports::Chat
14
+ include Supports::Uploads
15
+ include Supports::NickList
16
+ include Supports::Searches
17
+ include Supports::Downloads
18
+ include Supports::Persistence
19
+ include Supports::Timeout
20
+ include Supports::RemoteFileList
21
+ include Supports::LocalFileList
21
22
 
22
23
  configure do |config|
23
24
  config.download_dir = '/tmp/fargo/downloads'
25
+ config.config_dir = '/tmp/fargo/config'
24
26
  config.address = IPSocket.getaddress(Socket.gethostname)
25
27
  config.passive = false
26
28
  config.nick = 'fargo'
@@ -33,6 +35,8 @@ module Fargo
33
35
  config.password = ''
34
36
  config.speed = 'DSL'
35
37
  config.email = nil
38
+
39
+ config.override_share_size = 5368709121 # 5 GB + 1 byte
36
40
  end
37
41
 
38
42
  attr_reader :hub, :channel
@@ -54,21 +58,23 @@ module Fargo
54
58
  Fargo.logger.debug e.backtrace.join("\n")
55
59
  }
56
60
 
57
- EventMachine.connect config.hub_address, config.hub_port,
58
- Fargo::Protocol::Hub do |conn|
59
- @hub = conn
60
- @hub.client = self
61
- end
62
-
63
- unless config.passive
64
- EventMachine.start_server '0.0.0.0', config.active_port,
65
- Fargo::Protocol::Download do |conn|
66
- conn.client = self
61
+ run_callbacks :connect do
62
+ EventMachine.connect config.hub_address, config.hub_port,
63
+ Protocol::Hub do |conn|
64
+ @hub = conn
65
+ @hub.client = self
67
66
  end
68
67
 
69
- EventMachine.open_datagram_socket '0.0.0.0', config.search_port,
70
- Fargo::Protocol::DC do |conn|
71
- conn.client = self
68
+ unless config.passive
69
+ EventMachine.start_server '0.0.0.0', config.active_port,
70
+ Protocol::Peer do |conn|
71
+ conn.client = self
72
+ end
73
+
74
+ EventMachine.open_datagram_socket '0.0.0.0', config.search_port,
75
+ Protocol::DC do |conn|
76
+ conn.client = self
77
+ end
72
78
  end
73
79
  end
74
80
  end
@@ -83,7 +89,7 @@ module Fargo
83
89
  end
84
90
 
85
91
  def description
86
- "<fargo V:#{Fargo::VERSION},M:#{config.passive ? 'P' : 'A'},H:1/0/0,S:#{open_slots},Dt:1.2.6/W>"
92
+ "<fargo V:#{VERSION},M:#{config.passive ? 'P' : 'A'},H:1/0/0,S:#{open_upload_slots},Dt:1.2.6/W>"
87
93
  end
88
94
 
89
95
  end
data/lib/fargo/parser.rb CHANGED
@@ -1,12 +1,12 @@
1
1
  module Fargo
2
2
  module Parser
3
-
3
+
4
4
  #
5
5
  # See <http://www.teamfair.info/DC-Protocol.htm> for more information
6
6
  #
7
- @@commandmatch = /\$(.*)$/
7
+ @@commandmatch = /^\$(.*)$/
8
8
  @@messagematch = /^<(.*?)> (.*)$/
9
-
9
+
10
10
  # TODO: Supports, UserIP, ops command
11
11
  # Client - hub commands
12
12
  @@validatedenied = /^ValidateDenide/
@@ -24,35 +24,39 @@ module Fargo
24
24
  @@hubto = /^To: (.*?) From: Hub \$(.*)$/
25
25
  @@ctm = /^ConnectToMe (.*?) (.*?):(.*?)$/
26
26
  @@nicklist = /^NickList (.*?)$/
27
- @@psr = /^SR (.*?) (.*?)\005(.*?) (.*?)\/(.*?)\005(.*?) \((.*?):(.*?)\)$/
27
+ @@psr = /^SR (.*?) (.*?)\005(.*?) (.*?)\/(.*?)\005(.*?) \((.*?):(.*?)\)(?:\005.*)?$/
28
+ @@psrd = /^SR (.*?) (.*?) (.*?)\/(.*?)\005(.*?) \((.*?):(.*?)\)(?:\005.*)?$/
28
29
  @@psearch = /^Search Hub:(.*) (.)\?(.)\?(.*)\?(.)\?(.*)$/
29
30
  @@search = /^Search (.*):(.*) (.)\?(.)\?(.*)\?(.)\?(.*)$/
30
31
  @@oplist = /^OpList (.*?)$/
31
32
  @@botlist = /^BotList (.*?)$/
32
33
  @@quit = /^Quit (.*)$/
33
- @@sr = /^SR (.*?) (.*?)\005(.*?) (.*?)\/(.*?)\005(.*?) (.*?):(.*?)$/
34
34
  @@rctm = /^RevConnectToMe (.*?) (.*?)$/
35
-
35
+
36
36
  # Client to client commands
37
- @@mynick = /^MyNick (.*)$/
38
- @@key = /^Key (.*)$/
39
- @@direction = /^Direction (Download|Upload) (\d+)$/
40
- @@get = /^Get (.*)\$(\d+)$/
41
- @@send = /^Send$/
42
- @@filelength = /^FileLength (.*?)$/
43
- @@getlistlen = /^GetListLen$/
44
- @@maxedout = /^MaxedOut$/
45
- @@supports = /^Supports (.*)$/
46
- @@error = /^Error (.*)$/
47
- @@ugetblock = /^UGetBlock (.*?) (.*?) (.*)$/
48
- @@adcsnd = /^ADCSND (.*?) (.*?) (.*?) (.*?)$/
49
- @@adcsnd_zl1 = /^ADCSND (.*?) (.*?) (.*?) (.*?) ZL1$/
50
-
37
+ @@mynick = /^MyNick (.*)$/
38
+ @@key = /^Key (.*)$/
39
+ @@direction = /^Direction (Download|Upload) (\d+)$/
40
+ @@get = /^Get (.*)\$(\d+)$/
41
+ @@getzblock = /^U?GetZBlock (.*?) (.*?) (.*?)$/
42
+ @@send = /^Send$/
43
+ @@filelength = /^FileLength (.*?)$/
44
+ @@getlistlen = /^GetListLen$/
45
+ @@maxedout = /^MaxedOut$/
46
+ @@supports = /^Supports (.*)$/
47
+ @@error = /^Error (.*)$/
48
+ @@cancel = /^Cancel$/
49
+ @@canceled = /^Canceled$/
50
+ @@failed = /^Failed (.*)$/
51
+ @@sending = /^Sending (.*)$/
52
+ @@getblock = /^U?GetBlock (.*?) (.*?) (.*)$/
53
+ @@adcsnd = /^ADCSND (.*?) (.*?) (.*?) (.*?)( ZL1)?$/
54
+ @@adcget = /^ADCGET (.*?) (.*?) (.*?) (.*?)( ZL1)?$/
55
+
51
56
  def parse_message text
52
57
  case text
53
58
  when @@commandmatch then parse_command_message $1
54
59
  when @@messagematch then {:type => :chat, :from => $1, :text => $2}
55
- when '' then {:type => :garbage}
56
60
  else {:type => :mystery, :text => text}
57
61
  end
58
62
  end
@@ -64,58 +68,85 @@ module Fargo
64
68
  when @@badpass then {:type => :badpass}
65
69
  when @@lock then {:type => :lock, :lock => $1}
66
70
  when @@hubname then {:type => :hubname, :name => $1}
67
- when @@hubname then {:type => :hubfull}
71
+ when @@hubfull then {:type => :hubfull}
68
72
  when @@hubtopic then {:type => :hubtopic, :topic => $1}
69
- when @@hello then {:type => :hello, :who => $1}
70
- when @@myinfo then {:type => :myinfo, :nick => $1, :interest => $2, :speed => $3,
73
+ when @@hello then {:type => :hello, :nick => $1}
74
+ when @@myinfo then {:type => :myinfo, :nick => $1,
75
+ :interest => $2, :speed => $3,
71
76
  :email => $4, :sharesize => $5.to_i}
72
- when @@myinfo2 then {:type => :myinfo, :nick=> $1, :interest => $2, :sharesize=> 0}
73
- when @@to then {:type => :privmsg, :to => $1, :from => $2, :text => $3}
74
- when @@hubto then {:type => :privmsg, :to => $1, :from => "Hub", :text => $2}
75
- when @@ctm then {:type => :connect_to_me, :nick => $1, :address => $2,
76
- :port => $3.to_i}
77
- when @@nicklist then {:type => :nick_list, :nicks => $1.split(/\$\$/)}
78
- when @@psr then {:type => :search_result, :nick => $1, :file => $2,
79
- :size => $3.to_i, :open_slots => $4.to_i, :slots => $5.to_i,
80
- :hub => $6, :address => $7,
77
+ when @@myinfo2 then {:type => :myinfo, :nick=> $1,
78
+ :interest => $2, :sharesize => 0}
79
+ when @@to then {:type => :privmsg, :to => $1, :from => $2,
80
+ :text => $3}
81
+ when @@hubto then {:type => :privmsg, :to => $1,
82
+ :from => 'Hub', :text => $2}
83
+ when @@ctm then {:type => :connect_to_me, :nick => $1,
84
+ :address => $2, :port => $3.to_i}
85
+ when @@nicklist then {:type => :nick_list,
86
+ :nicks => $1.split('$$')}
87
+ when @@psr then {:type => :search_result, :nick => $1,
88
+ :file => $2, :size => $3.to_i,
89
+ :open_slots => $4.to_i, :slots => $5.to_i,
90
+ :hub => $6, :address => $7,
81
91
  :port => $8.to_i}
82
- when @@psearch then {:type => :search, :searcher => $1, :restrict_size => $2,
83
- :min_size => $3.to_i, :size => $4.to_i, :filetype => $5,
92
+ when @@psrd then {:type => :search_result, :nick => $1,
93
+ :dir => $2,
94
+ :open_slots => $3.to_i, :slots => $4.to_i,
95
+ :hub => $5, :address => $6,
96
+ :port => $7.to_i}
97
+ when @@psearch then {:type => :search, :searcher => $1,
98
+ :restrict_size => $2 == 'T',
99
+ :is_minimum_size => $3 == 'F',
100
+ :size => $4.to_i, :filetype => $5.to_i,
84
101
  :pattern => $6}
85
- when @@search then {:type => :search, :address => $1, :port => $2.to_i,
86
- :restrict_size => $3,
87
- :min_size => $4.to_i, :size => $5.to_i, :filetype => $6,
88
- :pattern => $7}
89
- when @@oplist then {:type => :op_list, :nicks => $1.split(/\$\$/)}
90
- when @@oplist then {:type => :bot_list, :nicks => $1.split(/\$\$/)}
91
- when @@quit then {:type => :quit, :who => $1}
92
- when @@sr then {:type => :search_result, :nick => $2, :file => $3,
93
- :size => $4.to_i, :open_slots => $5.to_i, :slots => $6.to_i,
94
- :hubname => $7}
102
+ when @@search then {:type => :search, :address => $1,
103
+ :port => $2.to_i,
104
+ :restrict_size => $3 == 'T',
105
+ :is_minimum_size => $4 == 'F',
106
+ :size => $5.to_i,
107
+ :filetype => $6.to_i, :pattern => $7}
108
+ when @@oplist then {:type => :op_list,
109
+ :nicks => $1.split('$$')}
110
+ when @@oplist then {:type => :bot_list,
111
+ :nicks => $1.split('$$')}
112
+ when @@quit then {:type => :quit, :nick => $1}
95
113
  when @@rctm then {:type => :revconnect, :who => $1}
96
-
114
+
97
115
  when @@mynick then {:type => :mynick, :nick => $1}
98
116
  when @@key then {:type => :key, :key => $1}
99
- when @@direction then {:type => :direction, :direction => $1.downcase, :number => $3.to_i}
100
- when @@get then {:type => :get, :path => $1, :offset => $2.to_i - 1}
117
+ when @@direction then {:type => :direction,
118
+ :direction => $1.downcase,
119
+ :number => $3.to_i}
120
+ when @@get then {:type => :get, :file => $1,
121
+ :offset => $2.to_i - 1, :size => -1}
101
122
  when @@send then {:type => :send}
102
123
  when @@filelength then {:type => :file_length, :size => $1.to_i}
103
124
  when @@getlistlen then {:type => :getlistlen}
104
125
  when @@maxedout then {:type => :noslots}
105
- when @@supports then {:type => :supports, :extensions => $1.split(' ')}
126
+ when @@supports then {:type => :supports,
127
+ :extensions => $1.split(' ')}
106
128
  when @@error then {:type => :error, :message => $1}
107
- when @@adcsnd_zl1 then {:type => :adcsnd, :kind => $1, :tth => $2, :offset => $3.to_i,
108
- :size => $4.to_i, :zlib => true}
109
- when @@adcsnd then {:type => :adcsnd, :kind => $1, :tth => $2, :offset => $3.to_i,
110
- :size => $4.to_i}
111
- when @@ugetblock then {:type => :ugetblock, :start => $1.to_i, :finish => $2.to_i,
112
- :path => $3}
113
- when @@userip then
129
+ when @@failed then {:type => :error, :message => $1}
130
+ when @@cancel then {:type => :cancel}
131
+ when @@canceled then {:type => :canceled}
132
+ when @@sending then {:type => :sending, :size => $1.to_i}
133
+ when @@adcsnd then {:type => :adcsnd, :kind => $1, :file => $2,
134
+ :offset => $3.to_i, :size => $4.to_i,
135
+ :zlib => !$5.nil?}
136
+ when @@adcget then {:type => :adcget, :kind => $1, :file => $2,
137
+ :offset => $3.to_i, :size => $4.to_i,
138
+ :zlib => !$5.nil?}
139
+ when @@getzblock then {:type => :getblock, :file => $3,
140
+ :size => $2.to_i, :offset => $1.to_i,
141
+ :zlib => true}
142
+ when @@getblock then {:type => :getblock, :start => $1.to_i,
143
+ :size => $2.to_i, :file => $3}
144
+ when @@userip then
114
145
  h = {:type => :userip, :users => {}}
115
- $1.split("$$").map{ |s| h[:users][s.split(' ')[0]] = s.split(' ')[1]}
146
+ $1.split('$$').map{ |s| h[:users][s.split(' ')[0]] = s.split(' ')[1]}
116
147
  h
117
- else {:type => :mystery, :text => text}
148
+ else {:type => :mystery, :text => '$' + text}
118
149
  end
119
150
  end
120
151
  end
121
- end
152
+ end
@@ -2,7 +2,7 @@ module Fargo
2
2
  module Protocol
3
3
  module DC
4
4
 
5
- include Fargo::Parser
5
+ include Parser
6
6
  attr_accessor :client
7
7
 
8
8
  def post_init
@@ -24,14 +24,27 @@ module Fargo
24
24
  send_data data
25
25
  end
26
26
 
27
+ def receive_data_chunk chunk
28
+ chunk.chomp! '|'
29
+ Fargo.logger.debug "#{self}: Received: #{chunk.inspect}"
30
+ hash = parse_message chunk
31
+ receive_message hash[:type], hash
32
+ end
33
+
34
+ def parse_data?
35
+ true
36
+ end
37
+
27
38
  def receive_data data
28
- @received_data << data
39
+ if parse_data?
40
+ @received_data << data
29
41
 
30
- while message = @received_data.slice!(/[^\|]+\|/)
31
- message.chomp! '|'
32
- Fargo.logger.debug "#{self}: Received: #{message.inspect}"
33
- hash = parse_message message
34
- receive_message hash[:type], hash
42
+ while parse_data? && chunk = @received_data.slice!(/[^\|]+\|/)
43
+ receive_data_chunk chunk
44
+ end
45
+ else
46
+ receive_data_chunk @received_data + data
47
+ @received_data = ''
35
48
  end
36
49
  end
37
50
 
@@ -39,9 +52,12 @@ module Fargo
39
52
  {}
40
53
  end
41
54
 
55
+ def connection_type
56
+ :dc
57
+ end
58
+
42
59
  def unbind
43
60
  if client
44
- connection_type = self.class.name.split('::').last.downcase
45
61
  args = [:"#{connection_type}_disconnected", publish_args]
46
62
  client.channel << args
47
63
  end
@@ -1,12 +1,16 @@
1
1
  module Fargo
2
2
  module Protocol
3
- class Hub < EventMachine::Connection
3
+ module Hub
4
4
 
5
- include Fargo::Protocol::DC
6
- include Fargo::Utils
5
+ include Utils
6
+ include Protocol::DC
7
7
 
8
8
  attr_reader :hubname
9
9
 
10
+ def connection_type
11
+ :hub
12
+ end
13
+
10
14
  # See <http://www.teamfair.info/DC-Protocol.htm> for specifics on
11
15
  # the DC protocol
12
16
  def receive_message type, message
@@ -20,10 +24,10 @@ module Fargo
20
24
  when :getpass
21
25
  send_message 'MyPass', @client.config.password
22
26
  when :badpass, :hubfull
23
- Fargo.logger.warn "Disconnecting because of: #{message.inspect}"
27
+ Fargo.logger.info "Disconnecting because of: #{message.inspect}"
24
28
  close_connection_after_writing
25
29
  when :hello
26
- if message[:who] == @client.config.nick
30
+ if message[:nick] == @client.config.nick
27
31
  Fargo.logger.info "Connected to DC Hub #{@hubname}"
28
32
  @validated = true
29
33
 
@@ -36,37 +40,54 @@ module Fargo
36
40
  end
37
41
 
38
42
  when :connect_to_me
39
- if !@client.nicks.include?(message[:nick])
40
- Fargo.logger.info "Invalid connect_to_me request from: #{message[:nick]}"
41
- return
42
- end
43
-
44
43
  EventMachine.connect message[:address], message[:port],
45
- Fargo::Protocol::Download do |conn|
44
+ Protocol::Peer do |conn|
46
45
  conn.client = @client
47
46
  conn.send_lock # We connect first, we send lock first
48
47
  end
49
48
 
50
49
  when :search
51
50
  # Let the client handle the results
52
- @results = @client.search_files message
51
+ search = Search.new message
52
+ @listings = @client.search_local_listings search
53
53
 
54
- # Send all the results to the peer. Take care of active/passive
55
- # connections
56
- @results.each { |r|
57
- if message[:address]
58
- r.active_send @client.config.nick, message[:ip], message[:port]
54
+ @results = @listings.map do |l|
55
+ file = l.name.gsub '/', "\\"
56
+ if File.directory? l.name
57
+ s = file
59
58
  else
60
- send_message 'SR', "#{@client.config.nick} #{r}"
59
+ s = "#{file}\005#{l.size}"
61
60
  end
62
- }
61
+
62
+ s + sprintf(" %d/%d\005%s (%s:%d)", @client.open_upload_slots,
63
+ @client.config.upload_slots,
64
+ 'TTH:' + l.tth,
65
+ @client.config.hub_address,
66
+ @client.config.hub_port)
67
+ end
68
+
69
+ # Send all the results to the peer. Take care of active/passive
70
+ # connections
71
+ if message[:address]
72
+ socket = EventMachine.open_datagram_socket '0.0.0.0', 0
73
+ @results.each{ |r|
74
+ socket.send_datagram "$SR #{@client.config.nick} #{r}|",
75
+ message[:address], message[:port]
76
+ }
77
+ socket.close_connection_after_writing
78
+ else
79
+ @results.each{ |r|
80
+ send_message 'SR',
81
+ "#{@client.config.nick} #{r}\005#{message[:searcher]}"
82
+ }
83
+ end
63
84
 
64
85
  when :revconnect
65
86
  if @client.config.passive
66
87
  send_message 'RevConnectToMe',
67
88
  "#{@client.config.nick} #{message[:who]}"
68
89
  else
69
- send_message 'ConnectToMe', "#{@client.config.nick} #{@client.config.address}:#{@client.config.extport}"
90
+ send_message 'ConnectToMe', "#{message[:who]} #{@client.config.address}:#{@client.config.active_port}"
70
91
  end
71
92
 
72
93
  # proxy this message on up the stack if we don't handle it
@@ -0,0 +1,114 @@
1
+ require 'zlib'
2
+
3
+ module Fargo
4
+ module Protocol
5
+ module Peer
6
+
7
+ include Utils
8
+ include Protocol::DC
9
+ include PeerDownload
10
+ include PeerUpload
11
+
12
+ attr_accessor :client
13
+
14
+ def connection_type
15
+ :peer
16
+ end
17
+
18
+ def post_init
19
+ super
20
+
21
+ set_comm_inactivity_timeout 20
22
+
23
+ @lock, @pk = generate_lock
24
+ @handshake_step = 0
25
+ end
26
+
27
+ def send_lock
28
+ @lock_sent = true
29
+ send_message 'MyNick', @client.config.nick
30
+ send_message 'Lock', "#{@lock} Pk=#{@pk}"
31
+ end
32
+
33
+ def supports
34
+ 'MiniSlots XmlBZList ADCGet TTHF ZLIG GetZBlock'
35
+ end
36
+
37
+ def receive_message type, message
38
+ case type
39
+ when :mynick
40
+ if @handshake_step == 0
41
+ @handshake_step = 1
42
+ @other_nick = message[:nick]
43
+
44
+ client.channel << [:download_opened,
45
+ publish_args.merge(:connection => self)]
46
+ @download = @client.lock_next_download! @other_nick, self
47
+
48
+ @direction = @download.nil? ? 'Upload' : 'Download'
49
+ else
50
+ error 'Premature disconnect when mynick received'
51
+ end
52
+
53
+ when :lock
54
+ if @handshake_step == 1
55
+ @remote_lock = message[:lock]
56
+ @handshake_step = 2
57
+
58
+ send_lock unless @lock_sent
59
+
60
+ send_message 'Supports', supports
61
+ send_message 'Direction', "#{@direction} #{@my_num = rand(10000)}"
62
+ send_message 'Key', generate_key(@remote_lock)
63
+ else
64
+ error 'Premature disconnect when lock received'
65
+ end
66
+
67
+ when :supports
68
+ if @handshake_step == 2
69
+ @client_extensions = message[:extensions]
70
+ @handshake_step = 3
71
+ else
72
+ error 'Premature disconnect when supports received'
73
+ end
74
+
75
+ when :direction
76
+ if @handshake_step == 3
77
+ @client_num = message[:number]
78
+ @handshake_step = 4
79
+ else
80
+ error 'Premature disconnect when direction received'
81
+ end
82
+
83
+ when :key
84
+ if @handshake_step == 4 && generate_key(@lock) == message[:key]
85
+ @handshake_step = 5
86
+
87
+ begin_download! if @direction == 'Download'
88
+
89
+ else
90
+ error 'Premature disconnect when key received'
91
+ end
92
+
93
+ # This wasn't handled by us, proxy it on up to the client
94
+ else
95
+ super
96
+
97
+ end
98
+ end
99
+
100
+ def publish_args
101
+ {:nick => @other_nick}
102
+ end
103
+
104
+ protected
105
+
106
+ def error message
107
+ Fargo.logger.warn @last_error = message
108
+
109
+ close_connection
110
+ end
111
+
112
+ end
113
+ end
114
+ end