fargo 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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