package Net::YahooMessenger::EventFactory;
use strict;
use Net::YahooMessenger;
use constant YMSG_LOGIN => 1;
use constant YMSG_LOGOUT => 2;
use constant YMSG_CHANGE_STATE => 3;
use constant YMSG_CHANGE_AVAILABLE => 4;
use constant YMSG_MESSAGE => 6;
use constant YMSG_NEW_FRIEND_ALERT => 15;
use constant YMSG_SERVER_IS_ALIVE => 76;
use constant YMSG_AUTH => 84;
use constant YMSG_BUDDY_LIST => 241;
use constant YMSG_BEGIN_AUTH => 87;
use constant ID => '1';
use constant BADDY_NAME => '7';
use constant NUMBER_OF_ONLINE_BADDY => '8';
use constant STATE => '10';
use constant SESSION_ID => '11';
use constant ONLINE_OR_OFFLINE => '13';
use constant STATE_OF_USER_DEFINITION => '19';
use constant BUSYNESS => '47';
use constant EVENT_CLASS => {
1 => 'Net::YahooMessenger::GoesOnline',
2 => 'Net::YahooMessenger::GoesOffline',
3 => 'Net::YahooMessenger::ChangeState',
4 => 'Net::YahooMessenger::ChangeState',
6 => 'Net::YahooMessenger::ReceiveMessage',
15 => 'Net::YahooMessenger::NewFriendAlert',
76 => 'Net::YahooMessenger::ServerIsAlive',
85 => 'Net::YahooMessenger::UserInfo',
87 => 'Net::YahooMessenger::ChallengeStart',
241 => 'Net::YahooMessenger::ReceiveBuddyList',
};
sub new {
my $class = shift;
my $connection = shift;
bless { connection => $connection }, $class;
}
sub create_by_raw_data {
my $self = shift;
my $connection = $self->{connection};
my ( $event_code, $identifier, $body ) = eval { $self->_get_message_body; };
if ($@) {
# print STDERR $@;
require Net::YahooMessenger::InvalidLogin;
return Net::YahooMessenger::InvalidLogin->new($connection);
}
my ( $code, $recipient, $private, $sender, @baddy ) = split /\xC0\x80/,
$body;
if ( $event_code == YMSG_LOGIN && lc $recipient eq lc $sender ) {
require Net::YahooMessenger::Login;
my $event = Net::YahooMessenger::Login->new($connection);
$event->source($body);
$event->from($sender);
$connection->identifier($identifier);
return $event if scalar $connection->buddy_list <= 0;
shift @baddy;
my $id = shift @baddy;
my $buddy;
for ( my $i = 0 ; $i < scalar @baddy ; $i += 2 ) {
if ( $baddy[$i] eq BADDY_NAME ) {
$buddy = $connection->get_buddy_by_name( $baddy[ $i + 1 ] );
}
elsif ( $baddy[$i] eq STATE ) {
$buddy->status( $baddy[ $i + 1 ] ) if $buddy;
}
elsif ( $baddy[$i] eq STATE_OF_USER_DEFINITION ) {
$buddy->custom_status( $baddy[ $i + 1 ] ) if $buddy;
}
elsif ( $baddy[$i] eq BUSYNESS ) {
$buddy->busy( $baddy[ $i + 1 ] ) if $buddy;
}
elsif ( $baddy[$i] eq SESSION_ID ) {
$buddy->session_id( $baddy[ $i + 1 ] ) if $buddy;
}
elsif ( $baddy[$i] eq ONLINE_OR_OFFLINE ) {
$buddy->online( $baddy[ $i + 1 ] ) if $buddy;
}
else { }
}
return $event;
}
else {
my $class = EVENT_CLASS->{$event_code}
|| 'Net::YahooMessenger::DummyEvent';
eval "require $class";
if ($@) {
# print STDERR $@;
require Net::YahooMessenger::UnImplementEvent;
my $event = Net::YahooMessenger::UnImplementEvent->new($connection);
$event->code($event_code);
$event->source($body);
return $event;
}
my $event = $class->new($connection);
$event->source($body);
return $event;
}
}
sub create_by_name {
my $self = shift;
my $class = 'Net::YahooMessenger::' . shift;
eval "require $class";
if ($@) {
warn "No event matched require failed : $@";
require Net::YahooMessenger::NullEvent;
return Net::YahooMessenger::NullEvent->new;
}
return $class->new( $self->{connection} );
}
sub _get_message_body {
my $self = shift;
my $handle = $self->{connection}->handle;
my %command;
my $header = $self->_recv_by_length(20);
my ( $signature, $version, $length, $event_code, $return, $identifier ) =
unpack "a4Cx3nnNN", $header;
die 'Wring protocol' if $signature ne Net::YahooMessenger->YMSG_STD_HEADER;
my $message = $self->_recv_by_length($length);
return ( $event_code, $identifier, $message );
}
sub _recv_by_length {
my $self = shift;
my $length = shift || 0;
my $handle = $self->{connection}->handle;
my $message = '';
while ( length $message < $length ) {
my $buff = '';
$handle->sysread( $buff, 1, 0 )
or die "Disconnect socket";
$message .= $buff;
}
if (0) {
print "\n";
print map { sprintf "%s ", $_ =~ /[\w\d]/ ? $_ : '.'; } split //,
$message;
print "\n";
print map { sprintf "%02x ", ord $_; } split //, $message;
}
return $message;
}
1;
__END__