/usr/local/CPAN/Net-MSN/Net/MSN/Base.pm
# Net::MSN::Base - Base class used by Net::MSN and Net::MSN::SB.
# Originally written by:
# Adam Swann - http://www.adamswann.com/library/2002/msn-perl/
# Modified by:
# David Radunz - http://www.boxen.net/
#
# $Id: Base.pm,v 1.6 2003/07/09 16:51:50 david Exp $
package Net::MSN::Base;
use strict;
use warnings;
BEGIN {
# Modules
# CPAN
use IO::Socket;
use IO::Select;
use Hash::Merge qw( merge );
# Package specific
use Net::MSN::Debug;
use vars qw($VERSION);
$VERSION = do { my @r=(q$Revision: 1.6 $=~/\d+/g); sprintf "%d."."%03d"x$#r,@r };
# construct global Select
$__PACKAGE__::Select = IO::Select->new();
# construct global Socks
$__PACKAGE__::Socks = {};
# Unique Transmission ID
$__PACKAGE__::TrID = -1;
}
sub new {
my ($class, %args) = @_;
my $self = bless({
'Version' => $VERSION,
'Debug' => 0,
'Debug_Lvl' => 0,
'Debug_Log' => '',
'Debug_STDERR' => 1,
'Debug_STDOUT' => 0,
'Debug_LogCaller' => 1,
'Debug_LogTime' => 1,
'Debug_LogLvl' => 1,
'_L' => '',
'_Log' => '',
'_Type' => 'NS'
}, ref($class) || $class);
$self->set_options(\%args);
$self->_new_Log_obj();
return $self;
}
sub set_options {
my ($self, $opts) = @_;
my %opts = %$opts;
foreach my $key (keys %opts) {
if (ref $opts{$key} eq 'HASH') {
$self->{$key} =
\%{ merge($opts{$key}, $self->{$key}) };
} else {
$self->{$key} = $opts{$key};
}
}
}
sub _new_Log_obj {
my ($self) = @_;
return if ((defined $self->{_L} && $self->{_L}) ||
(defined $self->{_Log} && $self->{_Log}));
# Create a new Net::MSN::Debug object for debug
$self->{_L} = new Net::MSN::Debug(
'Debug' => $self->{Debug},
'Level' => $self->{Debug_Lvl},
'LogFile' => $self->{Debug_Log},
'STDERR' => $self->{Debug_STDERR},
'STDOUT' => $self->{Debug_STDOUT},
'LogCaller' => $self->{Debug_LogCaller},
'LogTime' => $self->{Debug_LogTime},
'LogLevel' => $self->{Debug_LogLvl}
);
die "Unable to create L obj!\n"
unless (defined $self->{_L} && $self->{_L});
$self->{_Log} = $self->{_L}->get_log_obj();
die "Unable to create Log obj!\n"
unless (defined ($self->{_Log} && $self->{_Log}));
}
sub merge_opts {
my ($self, $defaults, $args) = @_;
return unless ((defined $defaults && ref $defaults eq 'HASH') ||
(defined $args && ref $args eq 'HASH'));
my %opts = %$defaults;
foreach my $key (keys %$args) {
if (ref $args->{$key} eq 'HASH') {
$opts{$key} =
\%{ merge($args->{$key}, $defaults->{$key}) };
} else {
$opts{$key} = $args->{$key};
}
}
return %opts;
}
sub construct_socket {
my ($self) = @_;
$self->{Socket} = $self->connect_socket(
$self->{_Host}, $self->{_Port}
);
$__PACKAGE__::Select->add($self->{Socket});
$__PACKAGE__::Socks->{$self->{Socket}->fileno} = \$self;
}
sub remove_socket {
my ($self) = @_;
if (defined $self->{Socket} && $self->{Socket}) {
my $fn = $self->{Socket}->fileno;
$__PACKAGE__::Select->remove($self->{Socket});
delete($__PACKAGE__::Socks->{$fn})
if (defined $fn && defined $__PACKAGE__::Socks->{$fn});
if ($self->{_Type} eq 'SB') {
$self->{_Log}('Disconnected from Switch Board: '. $self->{_Host}. ':'.
$self->{_Port}. ' (Handle: '. $self->{Handle}.
', Socket: '. $fn. ')', 2);
} else {
if (defined $self->{_LastHost} && defined $self->{_LastPort}) {
$self->{_Log}('Disconnected from Notification Server: '.
$self->{_LastHost}. ':'. $self->{_LastPort}.
' (Socket: '. $fn. ')', 2);
undef($self->{_LastHost});
undef($self->{_LastPort});
} else {
$self->{_Log}('Disconnected from Notification Server: '.
$self->{_Host}. ':'. $self->{_Port}.
' (Socket: '. $fn. ')', 2);
}
}
return $fn;
} else {
$self->{_Log}('Cant Disconnect, no socket is open!', 1);
}
}
sub disconnect_socket {
my ($self) = @_;
if (defined $self->{Socket} && $self->{Socket}) {
$self->remove_socket();
$self->{Socket}->close();
}
}
sub connect_socket {
my ($self, $host, $port) = @_;
my $socket = IO::Socket::INET->new(
PeerAddr => $host,
PeerPort => $port,
Proto => 'tcp'
) or die "$!";
my $fn = $socket->fileno;
if ($self->{_Type} eq 'SB') {
$self->{_Log}('Connected to Switch Board: '. $host. ':'.
$port. ' (Handle: '. $self->{Handle}. ', Socket: '. $fn. ')', 2);
} else {
$self->{_Log}('Connected to Notification Server: '. $host. ':'.
$port. ' (Socket: '. $fn. ')', 2);
}
return $socket;
}
sub cycle_socket {
my ($self, $host, $port) = @_;
($self->{_LastHost}, $self->{_LastPort}) =
($self->{_Host}, $self->{_Port});
($self->{_Host}, $self->{_Port}) = ($host, $port);
$self->disconnect_socket();
$self->construct_socket();
}
sub send {
my ($self, $cmd, $data) = @_;
die "MSN->send: No command specified!\n"
unless (defined $cmd && $cmd);
$cmd = (defined $cmd) ? $cmd : '';
$data = (defined $data) ? $data : '';
my $datagram = $cmd. ' '. ++$__PACKAGE__::TrID. ' '. $data. "\r\n";
$self->{Socket}->print($datagram);
chomp($datagram);
my $fn = $self->{Socket}->fileno;
$self->{_Log}('('. $fn. ')TX: '. $datagram, 3);
return length($datagram);
}
sub sendraw {
my ($self, $cmd, $data) = @_;
die "MSN->send: No command specified!\n"
unless (defined $cmd && $cmd);
$cmd = (defined $cmd) ? $cmd : '';
$data = (defined $data) ? $data : '';
my $datagram = $cmd. ' '. ++$__PACKAGE__::TrID. ' '. $data;
$self->{Socket}->print($datagram);
chomp($datagram);
my $fn = $self->{Socket}->fileno;
$self->{_Log}('('. $fn. ')TX: '. $datagram, 3);
return length($datagram);
}
sub sendnotrid {
my ($self, $cmd, $message) = @_;
die "MSN->send: No command specified!\n"
unless (defined $cmd && $cmd);
my $datagram = $cmd;
$datagram .= ' '. $message if (defined $message && $message);
$datagram .= "\r\n";
$self->{Socket}->print($datagram);
chomp($datagram);
my $fn = $self->{Socket}->fileno;
$self->{_Log}('('. $fn. ')TX: '. $datagram, 3);
return length($datagram);
}
return 1;