0
require 'cgi' # for entity-escaping
0
class DCProtocol < EventMachine::Connection
0
include EventMachine::Protocols::LineText2
0
+ CLIENT_NAME = "RubyBot"
0
+ CLIENT_VERSION = "0.1"
0
+ def self.registerClientVersion(name, version)
0
+ CLIENT_NAME.replace name
0
+ CLIENT_VERSION.replace version
0
def registerCallback(callback, &block)
0
@callbacks[callback] << block
0
- STDERR.puts "-> #{data
}" if @debug
0
+ STDERR.puts "-> #{data
.gsub(/[^\x20-\x7F]/, ".")}" if @debug
0
- STDERR.puts "<- #{line
}" if @debug
0
+ STDERR.puts "<- #{line
.gsub(/[^\x20-\x7F]/, ".")}" if @debug
0
line = unsanitize(line)
0
cmd = line.slice!(/^\S+/)
0
- # version - version number for the tag
0
# slots - number of slots to declare as open
0
def self.connect(host, port, nickname, args = {})
0
EventMachine::connect(host, port, self) do |c|
0
@config[:speed] ||= "Bot"
0
@config[:speed_class] ||= 1
0
- @config[:version] ||= "0.1"
0
yield c if block_given?
0
# this is us, we should respond
0
send_command "Version", "1,0091"
0
send_command "GetNickList"
0
- send_command "MyINFO", "$ALL #{@nickname} #{@config[:description]}<
RubyBot V:#{@config[:version]},M:P,H:1/0/0,S:#{@config[:slots]}>$", \
0
+ send_command "MyINFO", "$ALL #{@nickname} #{@config[:description]}<
#{CLIENT_NAME} V:#{CLIENT_VERSION},M:P,H:1/0/0,S:#{@config[:slots]}>$", \
0
"$#{@config[:speed]}#{@config[:speed_class].chr}$#{@config[:email]}$0$"
0
user = DCUser.new(self, nick)
0
class DCPeerProtocol < DCProtocol
0
XML_FILE_LISTING = <<EOF
0
<?xml version="1.0" encoding="utf-8"?>
0
-<FileListing Version="1" Generator="
RubyBot">
0
+<FileListing Version="1" Generator="
#{CLIENT_NAME} #{CLIENT_VERSION}">
0
<Directory Name="Send a /pm with !help for help">
0
- DCLST_FILE_LISTING = <<EOF
0
-Send a /pm with !help for help
0
- DCLST_FILE_LISTING_HE3 = he3_encode(DCLST_FILE_LISTING)
0
+ XML_FILE_LISTING_BZ2 = BZ2.bzip2(XML_FILE_LISTING)
0
-
attr_reader :remote_user, :host, :port0
+
SUPPORTED_EXTENSIONS = ["ADCGet", "XmlBZList", "TTHF"]0
+ attr_reader :remote_nick, :host, :port, :state
0
+ self.registerCallback :error do |peer, message|
0
+ peer.send_command "Error", message unless peer.state == :data
0
+ peer.close_connection_after_writing
0
# callbacks triggered from the peer always begin with peer_
0
def call_callback(name, *args)
0
@parent.call_callback "peer_#{name.to_s}".to_sym, self, *args
0
def connection_completed
0
send_command "MyNick", @parent.nickname
0
- send_command "Lock", "
FOO", "Pk=BAR"
0
+ send_command "Lock", "
EXTENDEDPROTOCOLABCABCABCABCABCABC", "Pk=#{CLIENT_NAME}#{CLIENT_VERSION}ABCABC"
0
- @remote_user = @parent.users[nick]
0
- if @remote_user.nil? then
0
- # why are we being connected to by someone not on the hub?
0
- @remote_user = DCUser.new(@parent, nick)
0
+ def get_file_io(filename)
0
+ if filename == "files.xml.bz2" then
0
+ StringIO.new(XML_FILE_LISTING_BZ2)
0
lock = line.split(" ")[0]
0
+ send_command "Supports", *SUPPORTED_EXTENSIONS if lock =~ /^EXTENDEDPROTOCOL/
0
send_command "Direction", "Upload", rand(0x7FFF)
0
send_command "Key", key
0
call_callback :error, "Unexpected peer direction: #{direction}"
0
- def cmd_GetListLen(line)
0
- send_command "ListLen", DCLST_FILE_LISTING_HE3.length
0
+ def cmd_Supports(line)
0
+ @supports = line.split(" ")
0
if line =~ /^([^$]+)\$(\d+)$/ then
0
offset = $2.to_i - 1 # it's 1-based
0
call_callback :get, @filename
0
- if @filename == "MyList.DcLst" then
0
- @fileio = StringIO.new(DCLST_FILE_LISTING_HE3)
0
+ @fileio = get_file_io(@filename)
0
send_command "FileLength", @fileio.size - @fileio.pos
0
close_connection_after_writing
0
- send_command "Error", "Unknown $Get format"
0
- close_connection_after_writing
0
+ call_callback :error, "Unknown $Get format"
0
+ if @fileio.nil?
or @state != :data then
0
# we haven't been asked for the file yet
0
send_command "Error", "Unexpected $Send"
0
close_connection_after_writing
0
data = @fileio.read(40906)
0
+ if line =~ /^(\w+) (.+) (\d+) (-?\d+)(?: (.+))?$/ then
0
+ flags = ($5 || "").split(" ")
0
+ if type == "file" then
0
+ fileio = get_file_io(identifier)
0
+ length = fileio.size - fileio.pos if length == -1
0
+ send_command "ADCSND", "file", identifier, startpos, length
0
+ send_data fileio.read(length)
0
+ send_command "Error", "File Not Available"
0
+ send_command "Error", "Unknown $ADCGET type: #{type}"
0
+ send_command "Error", "Unknown $ADCGET flags: #{flags.join(" ")}"
0
+ send_command "Error", "Unknown $ADCGET format"
0
+ def cmd_UGetBlock(line)
0
+ if line =~ /^(\d+) (-?\d+) (.+)$/ then
0
+ fileio = get_file_io(filename)
0
+ length = fileio.size - fileio.pos if length == -1
0
+ send_command "Sending", length
0
+ send_data fileio.read(length)
0
+ send_command "Failed", "File Not Available"
0
+ send_command "Failed", "Unknown $UGetBlock format"
Comments
No one has commented yet.