### CMail::In::imap
# module for checking for messages in imap mailboxes
package CMail::In::imap;
use strict;
BEGIN {
use CMail::In::Base;
use vars qw($VERSION @ISA);
$VERSION = do { my @r = (q$Revision: 1.2 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r };
@ISA = qw( CMail::In::Base );
}
use IO::Socket;
use vars qw(%connections %cmdnum);
# For keeping the connection cache, so we don't have to reconnect multiple
# times if we're checking multiple mailboxes on the same IMAP server
%connections = ();
# For keeping the current command number of different imap connections
%cmdnum = ();
# methods
sub count {
my $self = shift;
my($user,$pass,$host,$port,$path) = $self->parse_uri;
$self->{user} = $user;
$self->{host} = $host;
$self->{port} = $port;
my $verbose = $self->{verbose};
$path =~ s!^/!!; # get rid of starting slash
$path = 'INBOX' if ( $path =~ /^\s*$/ );
warn "imap: Getting socket for $host.\n" if $verbose > 1;
my $socket = $self->connect_login($host,$port,$user,$pass);
# Send STAT
warn "imap: Sending STATUS $path (MESSAGES UNSEEN) to server.\n"
if $verbose > 1;
my $resp = $self->send_cmd($socket,"STATUS $path (MESSAGES UNSEEN)");
return comm_error($resp) unless $resp =~ /\(MESSAGES (\d+) UNSEEN (\d+)\)/;
warn "imap: Server said there are $1 messages, $2 new.\n" if $verbose;
return($1,$2);
}
# internal methods
# connect_login($host,$port,$user,$pass) - opens a socket to the given
# host and port and returns it. If someone wants to implement SSL, I
# suggest overloading just this function, if that's all that's required.
sub connect_login {
my $self = shift;
my $host = shift;
my $port = shift || '143';
my $user = shift;
my $pass = shift;
my $id = "$host:$port:$user";
if (defined $connections{$id}) {
$connections{$id}->{usage}++;
return $connections{$id}->{socket};
}
my $socket = IO::Socket::INET->new(
PeerAddr => $host,
PeerPort => $port,
Proto => 'tcp',
);
if ( not defined $socket ) {
die "imap: couldn't open socket to $host:$port: $!\n";
}
$connections{$id} = {
'socket' => $socket,
'usage' => 1,
};
my $answer = $self->send_cmd($socket,"LOGIN $user $pass");
if ( $answer =~ /BAD|NO/ ) {
die "imap: couldn't login to $host: $answer\n";
}
return $socket;
}
sub DESTROY {
my $self = shift;
my $host = $self->{host};
my $port = $self->{port} || 143;
my $user = $self->{user};
my $id = "$host:$port:$user";
if ( defined $connections{$id} ) {
$connections{$id}->{usage}--;
if ($connections{$id}->{usage} < 1) {
my $socket = $connections{$id}->{socket};
$self->send_cmd($socket,"LOGOUT");
$socket->close;
}
}
}
sub send_cmd {
my $self = shift;
my $socket = shift;
my $command = shift;
$cmdnum{$socket}++;
my $num = $cmdnum{$socket};
#warn "C: 'a$num $command'\n";
$socket->print("a$num $command\r\n");
my $resp = '';
while ( $resp !~ /a$num/ ) {
my $line = $socket->getline;
$resp .= $line;
$line =~ s/\s+$//;
#warn "S: '$line'\n";
}
return $resp;
}
sub comm_error {
my $response = shift;
$response =~ s/\s+$//;
die "imap: server responded with negative '$response'\n";
return;
}
1;
syntax highlighted by Code2HTML, v. 0.9.1