/usr/local/CPAN/Net-Gnutella/Net/Gnutella/Packet/Reply.pm


package Net::Gnutella::Packet::Reply;
use Socket qw(inet_ntoa inet_aton);
use Carp;
use strict;
use vars qw/$VERSION $AUTOLOAD/;

$VERSION = $VERSION = "0.1";

# Use AUTOHANDLER to supply generic attribute methods
#
sub AUTOLOAD {
	my $self = shift;
	my $attr = $AUTOLOAD;
	$attr =~ s/.*:://;
	return unless $attr =~ /[^A-Z]/; # skip DESTROY and all-cap methods
	croak sprintf "invalid attribute method: %s->%s()", ref($self), $attr unless exists $self->{_attr}->{lc $attr};
	$self->{_attr}->{lc $attr} = shift if @_;
	return $self->{_attr}->{lc $attr};
}

sub new {
	my $proto = shift;
	my %args = @_;

	my $self = {
		_attr   => {
			msgid    => [],
			ttl      => 7,
			hops     => 1,
			function => 129,

			ip      => [],
			port    => 0,
			speed   => 0,
			results => [],
			guid    => [],
		},
	};

	bless $self, $proto;

	foreach my $key (keys %args) {
		my $lkey = lc $key;

		$self->$lkey($args{$key});
	}

	return $self;
}

sub ip {
	my $self = shift;

	if (@_) {
		if (ref($_[0]) eq 'ARRAY') {
			$self->{_attr}->{ip} = $_[0];
		} elsif ($_[0] =~ /^[\d.]+$/) {
			$self->{_attr}->{ip} = [ split(/\./, $_[0]) ];
		} elsif ($_[0] =~ /\D/) {
			$self->{_attr}->{ip} = [ split(/\./, inet_ntoa(inet_aton($_[0]))) ];
		}
	}

	return @{ $self->{_attr}->{ip} };
}

sub ip_as_string {
	my $self = shift;

	return join(".", @{ $self->{_attr}->{ip} });
}

sub parse {
	my $self = shift;
	my $data = shift;

	my $count = unpack("C",  substr($data, 0, 1, ''));
	my $port  = unpack("S",  substr($data, 0, 2, ''));
	my @ip    = unpack("C4", substr($data, 0, 4, ''));
	my $speed = unpack("L",  substr($data, 0, 4, ''));
	my @set;

	for (my $i = 0; $i < $count; $i++) {
		my $index = unpack("L", substr($data, 0, 4, ''));
		my $size  = unpack("L", substr($data, 0, 4, ''));
		my $name  = substr($data, 0, index($data, "\x00\x00"), '');
		my $extra;

		if (index($name, "\x00") != -1) {
			$extra = $name;
			$name  = substr($extra, 0, index($extra, "\x00"), '');

			substr($extra, 0, 1, '');
		}

		substr($data, 0, 2, '');

		push @set, [ $index, $size, $name, $extra ];
	}

	my @guid = unpack("L4", substr($data, 0, 16, ''));

	$self->port($port);
	$self->ip(\@ip);
	$self->speed($speed);
	$self->results(\@set);
	$self->guid(\@guid);
}

sub format {
	my $self = shift;
	my $data;

	my $results = $self->results;

	$data .= pack("C",  scalar @$results);
	$data .= pack("S",  $self->port);
	$data .= pack("C4", $self->ip);
	$data .= pack("L",  $self->speed);

	foreach my $res (@$results) {
		$data .= pack("L", $res->[0]);
		$data .= pack("L", $res->[1]);
		$data .= $res->[2];
		$data .= $data =~ /\x00\x00$/ ? "" : "\x00\x00";
	}

	$data .= pack("L4", @{ $self->guid });

	return $data;
}

1;