2011-01-22 09:35:31 +01:00
|
|
|
#####################################################################
|
|
|
|
# #
|
|
|
|
# Net::IRC -- Object-oriented Perl interface to an IRC server #
|
|
|
|
# #
|
|
|
|
# DCC.pm: An object for Direct Client-to-Client connections. #
|
|
|
|
# #
|
|
|
|
# Copyright (c) 1997 Greg Bacon & Dennis Taylor. #
|
|
|
|
# All rights reserved. #
|
|
|
|
# #
|
|
|
|
# This module is free software; you can redistribute or #
|
|
|
|
# modify it under the terms of Perl's Artistic License. #
|
|
|
|
# #
|
|
|
|
#####################################################################
|
|
|
|
# $Id: DCC.pm,v 1.1.1.1 2002/11/14 17:32:15 jmuhlich Exp $
|
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
package PBot::IRC::DCC; # pragma_ 2011/21/01
|
2011-01-22 09:35:31 +01:00
|
|
|
|
|
|
|
use strict;
|
|
|
|
|
2019-07-11 03:40:53 +02:00
|
|
|
use feature 'unicode_strings';
|
2011-01-22 09:35:31 +01:00
|
|
|
|
|
|
|
# --- #perl was here! ---
|
|
|
|
#
|
|
|
|
# The comments scattered throughout this module are excerpts from a
|
|
|
|
# log saved from one particularly surreal night on #perl. Ahh, the
|
|
|
|
# trials of being young, single, and drunk...
|
|
|
|
#
|
|
|
|
# ---------------------
|
|
|
|
# \merlyn has offered the shower to a randon guy he met in a bar.
|
|
|
|
# fimmtiu: Shower?
|
|
|
|
# \petey raises an eyebrow at \merlyn
|
|
|
|
# \merlyn: but he seems like a nice trucker guy...
|
|
|
|
# archon: you offered to shower with a random guy?
|
|
|
|
|
|
|
|
# Methods that can be shared between the various DCC classes.
|
2020-02-15 23:38:32 +01:00
|
|
|
package PBot::IRC::DCC::Connection; # pragma_ 2011/21/01
|
2011-01-22 09:35:31 +01:00
|
|
|
|
|
|
|
use Carp;
|
2020-02-15 23:38:32 +01:00
|
|
|
use Socket; # need inet_ntoa...
|
2011-01-22 09:35:31 +01:00
|
|
|
use strict;
|
|
|
|
|
|
|
|
sub fixaddr {
|
|
|
|
my ($address) = @_;
|
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
chomp $address; # just in case, sigh.
|
|
|
|
if ($address =~ /^\d+$/) { return inet_ntoa(pack "N", $address); }
|
|
|
|
elsif ($address =~ /^[12]?\d{1,2}\.[12]?\d{1,2}\.[12]?\d{1,2}\.[12]?\d{1,2}$/) { return $address; }
|
|
|
|
elsif ($address =~ tr/a-zA-Z//) { # Whee! Obfuscation!
|
2011-01-22 09:35:31 +01:00
|
|
|
return inet_ntoa(((gethostbyname($address))[4])[0]);
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
sub bytes_in { return shift->{_bin}; }
|
2011-01-22 09:35:31 +01:00
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
sub bytes_out { return shift->{_bout}; }
|
2011-01-22 09:35:31 +01:00
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
sub nick { return shift->{_nick}; }
|
2011-01-22 09:35:31 +01:00
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
sub socket { return shift->{_socket}; }
|
2011-01-22 09:35:31 +01:00
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
sub time { return time - shift->{_time}; }
|
2011-01-22 09:35:31 +01:00
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
sub debug { return shift->{_debug}; }
|
2011-01-22 09:35:31 +01:00
|
|
|
|
|
|
|
# Changes here 1998-04-01 by MJD
|
|
|
|
# Optional third argument `$block'.
|
|
|
|
# If true, don't break the input into lines... just process it in blocks.
|
|
|
|
sub _getline {
|
|
|
|
my ($self, $sock, $block) = @_;
|
|
|
|
my ($input, $line);
|
|
|
|
my $frag = $self->{_frag};
|
|
|
|
|
|
|
|
if (defined $sock->recv($input, 10240)) {
|
2020-02-15 23:38:32 +01:00
|
|
|
$frag .= $input;
|
|
|
|
if (length($frag) > 0) {
|
|
|
|
|
|
|
|
warn "Got " . length($frag) . " bytes from $sock\n" if $self->{_debug};
|
|
|
|
|
|
|
|
if ($block) { # Block mode (GET)
|
|
|
|
return $input;
|
|
|
|
|
|
|
|
} else { # Line mode (CHAT)
|
|
|
|
# We're returning \n's 'cause DCC's need 'em
|
|
|
|
my @lines = split /\012/, $frag, -1;
|
|
|
|
$lines[-1] .= "\012";
|
|
|
|
$self->{_frag} = ($frag !~ /\012$/) ? pop @lines : '';
|
|
|
|
return (@lines);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
|
|
|
|
# um, if we can read, i say we should read more than 0
|
|
|
|
# besides, recv isn't returning undef on closed
|
|
|
|
# sockets. getting rid of this connection...
|
|
|
|
|
|
|
|
warn "recv() received 0 bytes in _getline, closing connection.\n" if $self->{_debug};
|
|
|
|
|
|
|
|
$self->{_parent}->handler(
|
|
|
|
PBot::IRC::Event->new(
|
|
|
|
'dcc_close', # pragma_ 2011/21/01
|
|
|
|
$self->{_nick},
|
|
|
|
$self->{_socket},
|
|
|
|
$self->{_type}
|
|
|
|
)
|
|
|
|
);
|
|
|
|
$self->{_parent}->parent->removefh($sock);
|
|
|
|
$self->{_socket}->close;
|
|
|
|
$self->{_fh}->close if $self->{_fh};
|
|
|
|
return;
|
|
|
|
}
|
2011-01-22 09:35:31 +01:00
|
|
|
} else {
|
2020-02-15 23:38:32 +01:00
|
|
|
|
|
|
|
# Error, lets scrap this connection
|
|
|
|
|
|
|
|
warn "recv() returned undef, socket error in _getline()\n" if $self->{_debug};
|
|
|
|
|
|
|
|
$self->{_parent}->handler(
|
|
|
|
PBot::IRC::Event->new(
|
|
|
|
'dcc_close', # pragma_ 2011/21/01
|
|
|
|
$self->{_nick},
|
|
|
|
$self->{_socket},
|
|
|
|
$self->{_type}
|
|
|
|
)
|
|
|
|
);
|
|
|
|
$self->{_parent}->parent->removefh($sock);
|
|
|
|
$self->{_socket}->close;
|
|
|
|
$self->{_fh}->close if $self->{_fh};
|
|
|
|
return;
|
2011-01-22 09:35:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sub DESTROY {
|
|
|
|
my $self = shift;
|
2019-06-26 18:34:19 +02:00
|
|
|
|
2011-01-22 09:35:31 +01:00
|
|
|
# Only do the Disconnection Dance of Death if the socket is still
|
|
|
|
# live. Duplicate dcc_close events would be a Bad Thing.
|
2019-06-26 18:34:19 +02:00
|
|
|
|
2011-01-22 09:35:31 +01:00
|
|
|
if ($self->{_socket}->opened) {
|
2020-02-15 23:38:32 +01:00
|
|
|
$self->{_parent}->handler(
|
|
|
|
PBot::IRC::Event->new(
|
|
|
|
'dcc_close', # pragma_ 2011/21/01
|
|
|
|
$self->{_nick},
|
|
|
|
$self->{_socket},
|
|
|
|
$self->{_type}
|
|
|
|
)
|
|
|
|
);
|
|
|
|
$self->{_socket}->close;
|
|
|
|
close $self->{_fh} if $self->{_fh};
|
|
|
|
$self->{_parent}->{_parent}->parent->removeconn($self);
|
2011-01-22 09:35:31 +01:00
|
|
|
}
|
2019-06-26 18:34:19 +02:00
|
|
|
|
2011-01-22 09:35:31 +01:00
|
|
|
}
|
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
sub peer { return ($_[0]->{_nick}, "DCC " . $_[0]->{_type}); }
|
2011-01-22 09:35:31 +01:00
|
|
|
|
|
|
|
# -- #perl was here! --
|
|
|
|
# orev: hehe...
|
|
|
|
# Silmaril: to, not with.
|
|
|
|
# archon: heheh
|
|
|
|
# tmtowtdi: \merlyn will be hacked to death by a psycho
|
|
|
|
# archon: yeah, but with is much more amusing
|
|
|
|
|
|
|
|
# Connection handling GETs
|
2020-02-15 23:38:32 +01:00
|
|
|
package PBot::IRC::DCC::GET; # pragma_ 2011/21/01
|
2011-01-22 09:35:31 +01:00
|
|
|
|
|
|
|
use IO::Socket;
|
|
|
|
use Carp;
|
|
|
|
use strict;
|
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
@PBot::IRC::DCC::GET::ISA = qw(Net::IRC::DCC::Connection); # pragma_ 2011/21/01
|
2011-01-22 09:35:31 +01:00
|
|
|
|
|
|
|
sub new {
|
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
my (
|
|
|
|
$class, $container, $nick, $address,
|
|
|
|
$port, $size, $filename, $handle, $offset
|
|
|
|
) = @_;
|
2011-01-22 09:35:31 +01:00
|
|
|
my ($sock, $fh);
|
|
|
|
|
|
|
|
# get the address into a dotted quad
|
2020-02-15 23:38:32 +01:00
|
|
|
$address = &PBot::IRC::DCC::Connection::fixaddr($address); # pragma_ 2011/21/01
|
2011-01-22 09:35:31 +01:00
|
|
|
return if $port < 1024 or not defined $address or $size < 1;
|
|
|
|
|
|
|
|
$fh = defined $handle ? $handle : IO::File->new(">$filename");
|
|
|
|
|
2019-05-28 18:19:42 +02:00
|
|
|
unless (defined $fh) {
|
2011-01-22 09:35:31 +01:00
|
|
|
carp "Can't open $filename for writing: $!";
|
2020-02-15 23:38:32 +01:00
|
|
|
$sock = new IO::Socket::INET(
|
|
|
|
Proto => "tcp",
|
|
|
|
PeerAddr => "$address:$port"
|
|
|
|
) and $sock->close();
|
2011-01-22 09:35:31 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
binmode $fh; # I love this next line. :-)
|
2011-01-22 09:35:31 +01:00
|
|
|
ref $fh eq 'GLOB' ? select((select($fh), $|++)[0]) : $fh->autoflush(1);
|
2019-06-26 18:34:19 +02:00
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
$sock = new IO::Socket::INET(
|
|
|
|
Proto => "tcp",
|
|
|
|
PeerAddr => "$address:$port"
|
|
|
|
);
|
2011-01-22 09:35:31 +01:00
|
|
|
|
|
|
|
if (defined $sock) {
|
2020-02-15 23:38:32 +01:00
|
|
|
$container->handler(
|
|
|
|
PBot::IRC::Event->new(
|
|
|
|
'dcc_open', # pragma_ 2011/21/01
|
|
|
|
$nick,
|
|
|
|
$sock,
|
|
|
|
'get',
|
|
|
|
'get', $sock
|
|
|
|
)
|
|
|
|
);
|
2019-06-26 18:34:19 +02:00
|
|
|
|
2011-01-22 09:35:31 +01:00
|
|
|
} else {
|
|
|
|
carp "Can't connect to $address: $!";
|
|
|
|
close $fh;
|
|
|
|
return;
|
|
|
|
}
|
2019-06-26 18:34:19 +02:00
|
|
|
|
2011-01-22 09:35:31 +01:00
|
|
|
$sock->autoflush(1);
|
|
|
|
|
|
|
|
my $self = {
|
2020-02-15 23:38:32 +01:00
|
|
|
_bin => defined $offset ? $offset : 0, # bytes recieved so far
|
|
|
|
_bout => 0, # Bytes we've sent
|
|
|
|
_connected => 1,
|
|
|
|
_debug => $container->debug,
|
|
|
|
_fh => $fh, # FileHandle we will be writing to.
|
|
|
|
_filename => $filename,
|
|
|
|
_frag => '',
|
|
|
|
_nick => $nick, # Nick of person on other end
|
|
|
|
_parent => $container,
|
|
|
|
_size => $size, # Expected size of file
|
|
|
|
_socket => $sock, # Socket we're reading from
|
|
|
|
_time => time,
|
|
|
|
_type => 'GET',
|
|
|
|
};
|
2011-01-22 09:35:31 +01:00
|
|
|
|
|
|
|
bless $self, $class;
|
|
|
|
|
|
|
|
return $self;
|
|
|
|
}
|
|
|
|
|
|
|
|
# -- #perl was here! --
|
|
|
|
# \merlyn: we were both ogling a bartender named arley
|
|
|
|
# \merlyn: I mean carle
|
|
|
|
# \merlyn: carly
|
|
|
|
# Silmaril: man merlyn
|
|
|
|
# Silmaril: you should have offered HER the shower.
|
|
|
|
# \petey: all three of them?
|
|
|
|
|
|
|
|
sub parse {
|
|
|
|
my ($self) = shift;
|
|
|
|
|
|
|
|
my $line = $self->_getline($_[0], 'BLOCKS');
|
|
|
|
|
|
|
|
next unless defined $line;
|
2019-05-28 18:19:42 +02:00
|
|
|
unless (print {$self->{_fh}} $line) {
|
2020-02-15 23:38:32 +01:00
|
|
|
carp("Error writing to " . $self->{_filename} . ": $!");
|
|
|
|
close $self->{_fh};
|
|
|
|
$self->{_parent}->parent->removeconn($self);
|
|
|
|
$self->{_parent}->handler(
|
|
|
|
PBot::IRC::Event->new(
|
|
|
|
'dcc_close', # pragma_ 2011/21/01
|
|
|
|
$self->{_nick},
|
|
|
|
$self->{_socket},
|
|
|
|
$self->{_type}
|
|
|
|
)
|
|
|
|
);
|
|
|
|
$self->{_socket}->close;
|
|
|
|
return;
|
2011-01-22 09:35:31 +01:00
|
|
|
}
|
2019-06-26 18:34:19 +02:00
|
|
|
|
2011-01-22 09:35:31 +01:00
|
|
|
$self->{_bin} += length($line);
|
2019-06-26 18:34:19 +02:00
|
|
|
|
2011-01-22 09:35:31 +01:00
|
|
|
# confirm the packet we've just recieved
|
2020-02-15 23:38:32 +01:00
|
|
|
unless ($self->{_socket}->send(pack("N", $self->{_bin}))) {
|
|
|
|
carp "Error writing to DCC GET socket: $!";
|
|
|
|
close $self->{_fh};
|
|
|
|
$self->{_parent}->parent->removeconn($self);
|
|
|
|
$self->{_parent}->handler(
|
|
|
|
PBot::IRC::Event->new(
|
|
|
|
'dcc_close', # pragma_ 2011/21/01
|
|
|
|
$self->{_nick},
|
|
|
|
$self->{_socket},
|
|
|
|
$self->{_type}
|
|
|
|
)
|
|
|
|
);
|
|
|
|
$self->{_socket}->close;
|
|
|
|
return;
|
2011-01-22 09:35:31 +01:00
|
|
|
}
|
2019-06-26 18:34:19 +02:00
|
|
|
|
2011-01-22 09:35:31 +01:00
|
|
|
$self->{_bout} += 4;
|
|
|
|
|
|
|
|
# The file is done.
|
|
|
|
# If we close the socket, the select loop gets screwy because
|
|
|
|
# it won't remove its reference to the socket.
|
2020-02-15 23:38:32 +01:00
|
|
|
if ($self->{_size} and $self->{_size} <= $self->{_bin}) {
|
2011-01-22 09:35:31 +01:00
|
|
|
close $self->{_fh};
|
|
|
|
$self->{_parent}->parent->removeconn($self);
|
2020-02-15 23:38:32 +01:00
|
|
|
$self->{_parent}->handler(
|
|
|
|
PBot::IRC::Event->new(
|
|
|
|
'dcc_close', # pragma_ 2011/21/01
|
|
|
|
$self->{_nick},
|
|
|
|
$self->{_socket},
|
|
|
|
$self->{_type}
|
|
|
|
)
|
|
|
|
);
|
|
|
|
$self->{_socket}->close;
|
2011-01-22 09:35:31 +01:00
|
|
|
return;
|
|
|
|
}
|
2019-06-26 18:34:19 +02:00
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
$self->{_parent}->handler(
|
|
|
|
PBot::IRC::Event->new(
|
|
|
|
'dcc_update', # pragma_ 2011/21/01
|
|
|
|
$self->{_nick},
|
|
|
|
$self,
|
|
|
|
$self->{_type},
|
|
|
|
$self
|
|
|
|
)
|
|
|
|
);
|
2011-01-22 09:35:31 +01:00
|
|
|
}
|
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
sub filename { return shift->{_filename}; }
|
2011-01-22 09:35:31 +01:00
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
sub size { return shift->{_size}; }
|
2011-01-22 09:35:31 +01:00
|
|
|
|
|
|
|
sub close {
|
|
|
|
my ($self, $sock) = @_;
|
|
|
|
$self->{_fh}->close;
|
|
|
|
$self->{_parent}->parent->removeconn($self);
|
2020-02-15 23:38:32 +01:00
|
|
|
$self->{_parent}->handler(
|
|
|
|
PBot::IRC::Event->new(
|
|
|
|
'dcc_close', # pragma_ 2011/21/01
|
|
|
|
$self->{_nick},
|
|
|
|
$self->{_socket},
|
|
|
|
$self->{_type}
|
|
|
|
)
|
|
|
|
);
|
2011-01-22 09:35:31 +01:00
|
|
|
$self->{_socket}->close;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
# -- #perl was here! --
|
|
|
|
# \merlyn: I can't type... she created a numbner of very good drinks
|
|
|
|
# \merlyn: She's still at work
|
|
|
|
# \petey resists mentioning that there's "No manual entry
|
|
|
|
# for merlyn."
|
|
|
|
# Silmaril: Haven't you ever seen swingers?
|
|
|
|
# \merlyn: she's off tomorrow... will meet me at the bar at 9:30
|
|
|
|
# Silmaril: AWWWWwwww yeeeaAAHH.
|
|
|
|
# archon: waka chica waka chica
|
|
|
|
|
|
|
|
# Connection handling SENDs
|
2020-02-15 23:38:32 +01:00
|
|
|
package PBot::IRC::DCC::SEND; # pragma_ 2011/21/01
|
|
|
|
@PBot::IRC::DCC::SEND::ISA = qw(Net::IRC::DCC::Connection); # pragma_ 2011/21/01
|
2011-01-22 09:35:31 +01:00
|
|
|
|
|
|
|
use IO::File;
|
|
|
|
use IO::Socket;
|
|
|
|
use Carp;
|
|
|
|
use strict;
|
|
|
|
|
|
|
|
sub new {
|
|
|
|
|
|
|
|
my ($class, $container, $nick, $filename, $blocksize) = @_;
|
|
|
|
my ($size, $port, $fh, $sock, $select);
|
|
|
|
|
|
|
|
$blocksize ||= 1024;
|
|
|
|
|
|
|
|
# Shell-safe DCC filename stuff. Trying to prank-proof this
|
|
|
|
# module is rather difficult.
|
|
|
|
$filename =~ tr/a-zA-Z.+0-9=&()[]%\-\\\/:,/_/c;
|
|
|
|
$fh = new IO::File $filename;
|
|
|
|
|
|
|
|
unless (defined $fh) {
|
|
|
|
carp "Couldn't open $filename for reading: $!";
|
2020-02-15 23:38:32 +01:00
|
|
|
return;
|
2011-01-22 09:35:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
binmode $fh;
|
|
|
|
$fh->seek(0, SEEK_END);
|
|
|
|
$size = $fh->tell;
|
|
|
|
$fh->seek(0, SEEK_SET);
|
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
$sock = new IO::Socket::INET(
|
|
|
|
Proto => "tcp",
|
|
|
|
Listen => 1
|
|
|
|
);
|
2011-01-22 09:35:31 +01:00
|
|
|
|
|
|
|
unless (defined $sock) {
|
|
|
|
carp "Couldn't open DCC SEND socket: $!";
|
|
|
|
$fh->close;
|
|
|
|
return;
|
2019-06-26 18:34:19 +02:00
|
|
|
}
|
2011-01-22 09:35:31 +01:00
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
$container->ctcp(
|
|
|
|
'DCC SEND', $nick, $filename,
|
|
|
|
unpack("N", inet_aton($container->hostname())),
|
|
|
|
$sock->sockport(), $size
|
|
|
|
);
|
2011-01-22 09:35:31 +01:00
|
|
|
|
|
|
|
$sock->autoflush(1);
|
|
|
|
|
|
|
|
my $self = {
|
2020-02-15 23:38:32 +01:00
|
|
|
_bin => 0, # Bytes we've recieved thus far
|
|
|
|
_blocksize => $blocksize,
|
|
|
|
_bout => 0, # Bytes we've sent
|
|
|
|
_debug => $container->debug,
|
|
|
|
_fh => $fh, # FileHandle we will be reading from.
|
|
|
|
_filename => $filename,
|
|
|
|
_frag => '',
|
|
|
|
_nick => $nick,
|
|
|
|
_parent => $container,
|
|
|
|
_size => $size, # Size of file
|
|
|
|
_socket => $sock, # Socket we're writing to
|
|
|
|
_time => 0, # This gets set by Accept->parse()
|
|
|
|
_type => 'SEND',
|
2011-01-22 09:35:31 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
bless $self, $class;
|
2019-06-26 18:34:19 +02:00
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
$sock = PBot::IRC::DCC::Accept->new($sock, $self); # pragma_ 2011/21/01
|
2011-01-22 09:35:31 +01:00
|
|
|
|
|
|
|
unless (defined $sock) {
|
|
|
|
carp "Error in accept: $!";
|
|
|
|
$fh->close;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $self;
|
|
|
|
}
|
|
|
|
|
|
|
|
# -- #perl was here! --
|
|
|
|
# fimmtiu: So a total stranger is using your shower?
|
|
|
|
# \merlyn: yes... a total stranger is using my hotel shower
|
|
|
|
# Stupid coulda sworn \merlyn was married...
|
|
|
|
# \petey: and you have a date.
|
|
|
|
# fimmtiu: merlyn isn't married.
|
|
|
|
# \petey: not a bad combo......
|
|
|
|
# \merlyn: perhaps a adate
|
|
|
|
# \merlyn: not maerried
|
|
|
|
# \merlyn: not even sober. --)
|
|
|
|
|
|
|
|
sub parse {
|
|
|
|
my ($self, $sock) = @_;
|
|
|
|
my $size = ($self->_getline($sock, 1))[0];
|
|
|
|
my $buf;
|
|
|
|
|
|
|
|
# i don't know how useful this is, but let's stay consistent
|
|
|
|
$self->{_bin} += 4;
|
|
|
|
|
|
|
|
unless (defined $size) {
|
2020-02-15 23:38:32 +01:00
|
|
|
|
|
|
|
# Dang! The other end unexpectedly canceled.
|
|
|
|
carp(($self->peer)[1] . " connection to " . ($self->peer)[0] . " lost");
|
|
|
|
$self->{_fh}->close;
|
|
|
|
$self->{_parent}->parent->removefh($sock);
|
|
|
|
$self->{_parent}->handler(
|
|
|
|
PBot::IRC::Event->new(
|
|
|
|
'dcc_close', # pragma_ 2011/21/01
|
|
|
|
$self->{_nick},
|
|
|
|
$self->{_socket},
|
|
|
|
$self->{_type}
|
|
|
|
)
|
|
|
|
);
|
|
|
|
$self->{_socket}->close;
|
|
|
|
return;
|
2011-01-22 09:35:31 +01:00
|
|
|
}
|
2019-06-26 18:34:19 +02:00
|
|
|
|
2011-01-22 09:35:31 +01:00
|
|
|
$size = unpack("N", $size);
|
2019-06-26 18:34:19 +02:00
|
|
|
|
2011-01-22 09:35:31 +01:00
|
|
|
if ($size >= $self->{_size}) {
|
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
if ($self->{_debug}) {
|
|
|
|
warn "Other end acknowledged entire file ($size >= ",
|
|
|
|
$self->{_size}, ")";
|
|
|
|
}
|
|
|
|
|
2011-01-22 09:35:31 +01:00
|
|
|
# they've acknowledged the whole file, we outtie
|
|
|
|
$self->{_fh}->close;
|
|
|
|
$self->{_parent}->parent->removeconn($self);
|
2020-02-15 23:38:32 +01:00
|
|
|
$self->{_parent}->handler(
|
|
|
|
PBot::IRC::Event->new(
|
|
|
|
'dcc_close', # pragma_ 2011/21/01
|
|
|
|
$self->{_nick},
|
|
|
|
$self->{_socket},
|
|
|
|
$self->{_type}
|
|
|
|
)
|
|
|
|
);
|
|
|
|
$self->{_socket}->close;
|
2011-01-22 09:35:31 +01:00
|
|
|
return;
|
2019-06-26 18:34:19 +02:00
|
|
|
}
|
2011-01-22 09:35:31 +01:00
|
|
|
|
2019-06-26 18:34:19 +02:00
|
|
|
# we're still waiting for acknowledgement,
|
2011-01-22 09:35:31 +01:00
|
|
|
# better not send any more
|
|
|
|
return if $size < $self->{_bout};
|
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
unless (defined $self->{_fh}->read($buf, $self->{_blocksize})) {
|
2011-01-22 09:35:31 +01:00
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
if ($self->{_debug}) { warn "Failed to read from source file in DCC SEND!"; }
|
|
|
|
$self->{_fh}->close;
|
2011-01-22 09:35:31 +01:00
|
|
|
$self->{_parent}->parent->removeconn($self);
|
2020-02-15 23:38:32 +01:00
|
|
|
$self->{_parent}->handler(
|
|
|
|
PBot::IRC::Event->new(
|
|
|
|
'dcc_close', # pragma_ 2011/21/01
|
|
|
|
$self->{_nick},
|
|
|
|
$self->{_socket},
|
|
|
|
$self->{_type}
|
|
|
|
)
|
|
|
|
);
|
|
|
|
$self->{_socket}->close;
|
2011-01-22 09:35:31 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-05-28 18:19:42 +02:00
|
|
|
unless ($self->{_socket}->send($buf)) {
|
2011-01-22 09:35:31 +01:00
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
if ($self->{_debug}) { warn "send() failed horribly in DCC SEND" }
|
2011-01-22 09:35:31 +01:00
|
|
|
$self->{_fh}->close;
|
|
|
|
$self->{_parent}->parent->removeconn($self);
|
2020-02-15 23:38:32 +01:00
|
|
|
$self->{_parent}->handler(
|
|
|
|
PBot::IRC::Event->new(
|
|
|
|
'dcc_close', # pragma_ 2011/21/01
|
|
|
|
$self->{_nick},
|
|
|
|
$self->{_socket},
|
|
|
|
$self->{_type}
|
|
|
|
)
|
|
|
|
);
|
|
|
|
$self->{_socket}->close;
|
|
|
|
return;
|
2011-01-22 09:35:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
$self->{_bout} += length($buf);
|
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
$self->{_parent}->handler(
|
|
|
|
PBot::IRC::Event->new(
|
|
|
|
'dcc_update', # pragma_ 2011/21/01
|
|
|
|
$self->{_nick},
|
|
|
|
$self,
|
|
|
|
$self->{_type},
|
|
|
|
$self
|
|
|
|
)
|
|
|
|
);
|
2019-06-26 18:34:19 +02:00
|
|
|
|
2011-01-22 09:35:31 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
# -- #perl was here! --
|
|
|
|
# fimmtiu: Man, merlyn, you must be drunk to type like that. :)
|
|
|
|
# \merlyn: too many longislands.
|
|
|
|
# \merlyn: she made them strong
|
|
|
|
# archon: it's a plot
|
|
|
|
# \merlyn: not even a good amoun tof coke
|
|
|
|
# archon: she's in league with the guy in your shower
|
|
|
|
# archon: she gets you drunk and he takes your wallet!
|
|
|
|
|
|
|
|
# handles CHAT connections
|
2020-02-15 23:38:32 +01:00
|
|
|
package PBot::IRC::DCC::CHAT; # pragma_ 2011/21/01
|
|
|
|
@PBot::IRC::DCC::CHAT::ISA = qw(Net::IRC::DCC::Connection); # pragma_ 2011/21/01
|
2011-01-22 09:35:31 +01:00
|
|
|
|
|
|
|
use IO::Socket;
|
|
|
|
use Carp;
|
|
|
|
use strict;
|
|
|
|
|
|
|
|
sub new {
|
|
|
|
|
|
|
|
my ($class, $container, $type, $nick, $address, $port) = @_;
|
|
|
|
my ($sock, $self);
|
|
|
|
|
|
|
|
if ($type) {
|
2020-02-15 23:38:32 +01:00
|
|
|
|
2011-01-22 09:35:31 +01:00
|
|
|
# we're initiating
|
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
$sock = new IO::Socket::INET(
|
|
|
|
Proto => "tcp",
|
|
|
|
Listen => 1
|
|
|
|
);
|
2019-06-26 18:34:19 +02:00
|
|
|
|
2011-01-22 09:35:31 +01:00
|
|
|
unless (defined $sock) {
|
|
|
|
carp "Couldn't open DCC CHAT socket: $!";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
$sock->autoflush(1);
|
|
|
|
$container->ctcp(
|
|
|
|
'DCC CHAT', $nick, 'chat',
|
|
|
|
unpack("N", inet_aton($container->hostname)),
|
|
|
|
$sock->sockport()
|
|
|
|
);
|
|
|
|
|
|
|
|
$self = {
|
|
|
|
_bin => 0, # Bytes we've recieved thus far
|
|
|
|
_bout => 0, # Bytes we've sent
|
|
|
|
_connected => 1,
|
|
|
|
_debug => $container->debug,
|
|
|
|
_frag => '',
|
|
|
|
_nick => $nick, # Nick of the client on the other end
|
|
|
|
_parent => $container,
|
|
|
|
_socket => $sock, # Socket we're reading from
|
|
|
|
_time => 0, # This gets set by Accept->parse()
|
|
|
|
_type => 'CHAT',
|
|
|
|
};
|
2019-06-26 18:34:19 +02:00
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
bless $self, $class;
|
2019-06-26 18:34:19 +02:00
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
$sock = PBot::IRC::DCC::Accept->new($sock, $self); # pragma_ 2011/21/01
|
2011-01-22 09:35:31 +01:00
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
unless (defined $sock) {
|
|
|
|
carp "Error in DCC CHAT connect: $!";
|
|
|
|
return;
|
|
|
|
}
|
2011-01-22 09:35:31 +01:00
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
} else { # we're connecting
|
2011-01-22 09:35:31 +01:00
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
$address = &PBot::IRC::DCC::Connection::fixaddr($address); # pragma_ 2011/21/01
|
|
|
|
return if $port < 1024 or not defined $address;
|
2011-01-22 09:35:31 +01:00
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
$sock = new IO::Socket::INET(
|
|
|
|
Proto => "tcp",
|
|
|
|
PeerAddr => "$address:$port"
|
|
|
|
);
|
2011-01-22 09:35:31 +01:00
|
|
|
|
|
|
|
if (defined $sock) {
|
2020-02-15 23:38:32 +01:00
|
|
|
$container->handler(
|
|
|
|
PBot::IRC::Event->new(
|
|
|
|
'dcc_open', # pragma_ 2011/21/01
|
|
|
|
$nick,
|
|
|
|
$sock,
|
|
|
|
'chat',
|
|
|
|
'chat', $sock
|
|
|
|
)
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
carp "Error in DCC CHAT connect: $!";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$sock->autoflush(1);
|
|
|
|
|
|
|
|
$self = {
|
|
|
|
_bin => 0, # Bytes we've recieved thus far
|
|
|
|
_bout => 0, # Bytes we've sent
|
|
|
|
_connected => 1,
|
|
|
|
_nick => $nick, # Nick of the client on the other end
|
|
|
|
_parent => $container,
|
|
|
|
_socket => $sock, # Socket we're reading from
|
|
|
|
_time => time,
|
|
|
|
_type => 'CHAT',
|
|
|
|
};
|
|
|
|
|
|
|
|
bless $self, $class;
|
|
|
|
|
|
|
|
$self->{_parent}->parent->addfh(
|
|
|
|
$self->socket,
|
|
|
|
$self->can('parse'), 'r', $self
|
|
|
|
);
|
2011-01-22 09:35:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return $self;
|
|
|
|
}
|
|
|
|
|
|
|
|
# -- #perl was here! --
|
|
|
|
# \merlyn: tahtd be coole
|
|
|
|
# KTurner bought the camel today, so somebody can afford one
|
|
|
|
# more drink... ;)
|
|
|
|
# tmtowtdi: I've heard of things like this...
|
|
|
|
# \merlyn: as an experience. that is.
|
|
|
|
# archon: i can think of cooler things (;
|
|
|
|
# \merlyn: I don't realiy have that mch in my wallet.
|
|
|
|
|
|
|
|
sub parse {
|
|
|
|
my ($self, $sock) = @_;
|
|
|
|
|
|
|
|
foreach my $line ($self->_getline($sock)) {
|
2020-02-15 23:38:32 +01:00
|
|
|
return unless defined $line;
|
|
|
|
|
|
|
|
$self->{_bin} += length($line);
|
|
|
|
|
|
|
|
return undef if $line eq "\012";
|
|
|
|
$self->{_bout} += length($line);
|
|
|
|
|
|
|
|
$self->{_parent}->handler(
|
|
|
|
PBot::IRC::Event->new(
|
|
|
|
'chat', # pragma_ 2011/21/01
|
|
|
|
$self->{_nick},
|
|
|
|
$self->{_socket},
|
|
|
|
'chat',
|
|
|
|
$line
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
|
|
|
$self->{_parent}->handler(
|
|
|
|
PBot::IRC::Event->new(
|
|
|
|
'dcc_update', # pragma_ 2011/21/01
|
|
|
|
$self->{_nick},
|
|
|
|
$self,
|
|
|
|
$self->{_type},
|
|
|
|
$self
|
|
|
|
)
|
|
|
|
);
|
2011-01-22 09:35:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# Sends a message to a channel or person.
|
|
|
|
# Takes 2 args: the target of the message (channel or nick)
|
|
|
|
# the text of the message to send
|
|
|
|
sub privmsg {
|
|
|
|
my ($self) = shift;
|
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
unless (@_) { croak 'Not enough arguments to privmsg()'; }
|
2019-06-26 18:34:19 +02:00
|
|
|
|
2011-01-22 09:35:31 +01:00
|
|
|
# Don't send a CR over DCC CHAT -- it's not wanted.
|
|
|
|
$self->socket->send(join('', @_) . "\012");
|
|
|
|
}
|
|
|
|
|
|
|
|
# -- #perl was here! --
|
|
|
|
# \merlyn: this girl carly at the bar is aBABE
|
|
|
|
# archon: are you sure? you don't sound like you're in a condition to
|
|
|
|
# judge such things (;
|
|
|
|
# *** Stupid has set the topic on channel #perl to \merlyn is shit-faced
|
|
|
|
# with a trucker in the shower.
|
|
|
|
# tmtowtdi: uh, yeah...
|
|
|
|
# \merlyn: good topic
|
|
|
|
|
|
|
|
# Sockets waiting for accept() use this to shoehorn into the select loop.
|
2020-02-15 23:38:32 +01:00
|
|
|
package PBot::IRC::DCC::Accept; # pragma_ 2011/21/01
|
2011-01-22 09:35:31 +01:00
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
@PBot::IRC::DCC::Accept::ISA = qw(Net::IRC::DCC::Connection); # pragma_ 2011/21/01
|
2011-01-22 09:35:31 +01:00
|
|
|
use Carp;
|
2020-02-15 23:38:32 +01:00
|
|
|
use Socket; # we use a lot of Socket functions in parse()
|
2011-01-22 09:35:31 +01:00
|
|
|
use strict;
|
|
|
|
|
|
|
|
sub new {
|
|
|
|
my ($class, $sock, $parent) = @_;
|
|
|
|
my ($self);
|
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
$self = {
|
|
|
|
_debug => $parent->debug,
|
|
|
|
_nonblock => 1,
|
|
|
|
_socket => $sock,
|
|
|
|
_parent => $parent,
|
|
|
|
_type => 'accept',
|
|
|
|
};
|
2019-06-26 18:34:19 +02:00
|
|
|
|
2011-01-22 09:35:31 +01:00
|
|
|
bless $self, $class;
|
|
|
|
|
|
|
|
# Tkil's gonna love this one. :-) But what the hell... it's safe to
|
|
|
|
# assume that the only thing initiating DCCs will be Connections, right?
|
|
|
|
# Boy, we're not built for extensibility, I guess. Someday, I'll clean
|
|
|
|
# all of the things like this up.
|
|
|
|
$self->{_parent}->{_parent}->parent->addconn($self);
|
|
|
|
return $self;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub parse {
|
|
|
|
my ($self) = shift;
|
|
|
|
my ($sock);
|
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
$sock = $self->{_socket}->accept;
|
2011-01-22 09:35:31 +01:00
|
|
|
$self->{_parent}->{_socket} = $sock;
|
2020-02-15 23:38:32 +01:00
|
|
|
$self->{_parent}->{_time} = time;
|
2011-01-22 09:35:31 +01:00
|
|
|
|
|
|
|
if ($self->{_parent}->{_type} eq 'SEND') {
|
2020-02-15 23:38:32 +01:00
|
|
|
|
|
|
|
# ok, to get the ball rolling, we send them the first packet.
|
|
|
|
my $buf;
|
|
|
|
unless (defined $self->{_parent}->{_fh}->read($buf, $self->{_parent}->{_blocksize})) { return; }
|
|
|
|
unless (defined $sock->send($buf)) {
|
|
|
|
$sock->close;
|
|
|
|
$self->{_parent}->{_fh}->close;
|
|
|
|
$self->{_parent}->{_parent}->parent->removefh($sock);
|
|
|
|
$self->{_parent}->handler(
|
|
|
|
PBot::IRC::Event->new(
|
|
|
|
'dcc_close', # pragma_ 2011/21/01
|
|
|
|
$self->{_nick},
|
|
|
|
$self->{_socket},
|
|
|
|
$self->{_type}
|
|
|
|
)
|
|
|
|
);
|
|
|
|
$self->{_socket}->close;
|
|
|
|
return;
|
|
|
|
}
|
2011-01-22 09:35:31 +01:00
|
|
|
}
|
2019-06-26 18:34:19 +02:00
|
|
|
|
2011-01-22 09:35:31 +01:00
|
|
|
$self->{_parent}->{_parent}->parent->addconn($self->{_parent});
|
|
|
|
$self->{_parent}->{_parent}->parent->removeconn($self);
|
|
|
|
|
2020-02-15 23:38:32 +01:00
|
|
|
$self->{_parent}->{_parent}->handler(
|
|
|
|
PBot::IRC::Event-> # pragma_ 2011/21/01
|
|
|
|
new(
|
|
|
|
'dcc_open',
|
|
|
|
$self->{_parent}->{_nick},
|
|
|
|
$self->{_parent}->{_socket},
|
|
|
|
$self->{_parent}->{_type},
|
|
|
|
$self->{_parent}->{_type},
|
|
|
|
$self->{_parent}->{_socket}
|
|
|
|
)
|
|
|
|
);
|
2011-01-22 09:35:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
1;
|
|
|
|
|
|
|
|
__END__
|
|
|
|
|
|
|
|
=head1 NAME
|
|
|
|
|
|
|
|
Net::IRC::DCC - Object-oriented interface to a single DCC connection
|
|
|
|
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
|
|
|
|
Hard hat area: This section under construction.
|
|
|
|
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
|
|
|
|
This documentation is a subset of the main Net::IRC documentation. If
|
|
|
|
you haven't already, please "perldoc Net::IRC" before continuing.
|
|
|
|
|
|
|
|
Net::IRC::DCC defines a few subclasses that handle DCC CHAT, GET, and SEND
|
|
|
|
requests for inter-client communication. DCC objects are created by
|
|
|
|
C<Connection-E<gt>new_{chat,get,send}()> in much the same way that
|
|
|
|
C<IRC-E<gt>newconn()> creates a new connection object.
|
|
|
|
|
|
|
|
=head1 METHOD DESCRIPTIONS
|
|
|
|
|
|
|
|
This section is under construction, but hopefully will be finally written up
|
|
|
|
by the next release. Please see the C<irctest> script and the source for
|
|
|
|
details about this module.
|
|
|
|
|
|
|
|
=head1 AUTHORS
|
|
|
|
|
|
|
|
Conceived and initially developed by Greg Bacon E<lt>gbacon@adtran.comE<gt> and
|
|
|
|
Dennis Taylor E<lt>dennis@funkplanet.comE<gt>.
|
|
|
|
|
|
|
|
Ideas and large amounts of code donated by Nat "King" Torkington E<lt>gnat@frii.comE<gt>.
|
|
|
|
|
|
|
|
Currently being hacked on, hacked up, and worked over by the members of the
|
|
|
|
Net::IRC developers mailing list. For details, see
|
|
|
|
http://www.execpc.com/~corbeau/irc/list.html .
|
|
|
|
|
|
|
|
=head1 URL
|
|
|
|
|
|
|
|
Up-to-date source and information about the Net::IRC project can be found at
|
|
|
|
http://netirc.betterbox.net/ .
|
|
|
|
|
|
|
|
=head1 SEE ALSO
|
|
|
|
|
|
|
|
=over
|
|
|
|
|
|
|
|
=item *
|
|
|
|
|
|
|
|
perl(1).
|
|
|
|
|
|
|
|
=item *
|
|
|
|
|
|
|
|
RFC 1459: The Internet Relay Chat Protocol
|
|
|
|
|
|
|
|
=item *
|
|
|
|
|
|
|
|
http://www.irchelp.org/, home of fine IRC resources.
|
|
|
|
|
|
|
|
=back
|
|
|
|
|
|
|
|
=cut
|