This was done by switching to using Mail::IMAPTalk. No IMAPTalk does not
do the speaking but it "talks" to IMAP and it allows me to register a
callback. Much more efficient and timely.
Maybe someday I'll implement a mechanism of looking for other
announceEmail's on the LAN and have it inform the others that this
announceEmail will handle the announcement. This is because I run this
on both my desktop and my MacBook so while they're both in the same room
I hear the announcement twice. One solution would be to poll the LAN
and see if there are any more announceEmail processes and then use
IPC to communicate between them. Of course, if they are physically
very distant we probably want the announcement being a true broadcast.
-use|rname: User name to log in with (Default: $USER)
-p|assword: Password to use (Default: prompted)
-i|map: IMAP server to talk to (Default: defaria.com)
-use|rname: User name to log in with (Default: $USER)
-p|assword: Password to use (Default: prompted)
-i|map: IMAP server to talk to (Default: defaria.com)
- -s|leep: Number of minutes to sleep inbetween checking mail (Default: 1)
use FindBin;
use Getopt::Long;
use Pod::Usage;
use FindBin;
use Getopt::Long;
use Pod::Usage;
-use Net::IMAP::Simple;
-use Email::Simple;
use MIME::Base64;
use lib "$FindBin::Bin/../lib";
use MIME::Base64;
use lib "$FindBin::Bin/../lib";
use Utils;
my $defaultIMAPServer = 'defaria.com';
use Utils;
my $defaultIMAPServer = 'defaria.com';
-my $defaultSleeptime = 1;
my $IMAP;
my %unseen;
my $log;
my $IMAP;
my %unseen;
my $log;
username => $ENV{USER},
password => $ENV{PASSWORD},
imap => $defaultIMAPServer,
username => $ENV{USER},
password => $ENV{PASSWORD},
imap => $defaultIMAPServer,
- sleep => $defaultSleeptime,
} # logit
sub unseenMsgs() {
} # logit
sub unseenMsgs() {
+ $IMAP->select('inbox') or
+ $log->err("Unable to select inbox: " . get_last_error(), 1);
- for (my $i = 1; $i <= $IMAP->status; $i++) {
- $unseenMsgs{$i} = 0 unless $IMAP->seen($i);
- } # for
-
- return %unseenMsgs;
+ return map { $_=> 0 } @{$IMAP->search('not', 'seen')};
} # unseenMsgs
sub Connect2IMAP() {
$log->msg("Connecting to $opts{imap} as $opts{username}...", 1);
} # unseenMsgs
sub Connect2IMAP() {
$log->msg("Connecting to $opts{imap} as $opts{username}...", 1);
- $IMAP = Net::IMAP::Simple->new($opts{imap}) ||
- $log->err("Unable to connect to IMAP server $opts{imap}: " . $Net::IMAP::Simple::errstr, 1);
+ $IMAP = Mail::IMAPTalk->new(
+ Server => $opts{imap},
+ Username => $opts{username},
+ Password => $opts{password},
+ ) or $log->err("Unable to connect to IMAP server $opts{imap}: $@", 1);
- $log->msg("Logging onto $opts{imap} as $opts{username}...", 1);
-
- unless ($IMAP->login($opts{username}, $opts{password})) {
- $log->err("Login to $opts{imap} as $opts{username} failed: " . $IMAP->errstr, 1);
- } # unless
-
- $log->msg(' logged on');
-
- $IMAP->select('INBOX');
+ $IMAP->select('inbox');
# Setup %unseen to have each unseen message index set to 0 meaning not read
# aloud yet
# Setup %unseen to have each unseen message index set to 0 meaning not read
# aloud yet
} # Connect2IMAP
sub MonitorMail() {
} # Connect2IMAP
sub MonitorMail() {
- my $msg = "Now monitoring email for $opts{username}\@$opts{imap}";
-
- $log->msg($msg);
-
- my $cmd = "/usr/local/bin/gt \"$msg\"";
-
- my ($status, @output) = Execute $cmd;
-
while () {
# First close and reselect the INBOX to get its current status
debugit "Reconnecting to INBOX";
while () {
# First close and reselect the INBOX to get its current status
debugit "Reconnecting to INBOX";
for (keys %newUnseen) {
next if $unseen{$_};
for (keys %newUnseen) {
next if $unseen{$_};
- my @msglines = $IMAP->top($_);
-
- # What happens at INBOX 0? Does top return empty array?
- $log->err("Unable to get top for $_ - " . $IMAP->errstr(), 1) unless @msglines;
-
- my $email = Email::Simple->new(join '', @msglines);
-
- my $from = $email->header('From');
+ my $envelope = $IMAP->fetch($_, '(envelope)');
+ my $from = $envelope->{$_}{envelope}{From};
+ my $subject = $envelope->{$_}{envelope}{Subject};
+ $subject //= 'Unknown subject';
# Extract the name only when the email is of the format "name <email>"
if ($from =~ /^"?(.*?)"?\s*\<(\S*)>/) {
$from = $1 if $1 ne '';
} # if
# Extract the name only when the email is of the format "name <email>"
if ($from =~ /^"?(.*?)"?\s*\<(\S*)>/) {
$from = $1 if $1 ne '';
} # if
- my $subject = $email->header('Subject');
-
if ($subject =~ /=?\S+?(Q|B)\?(.+)\?=/) {
$subject = decode_base64($2);
} # if
if ($subject =~ /=?\S+?(Q|B)\?(.+)\?=/) {
$subject = decode_base64($2);
} # if
debugit "Speaking message from $from";
my $logmsg = "From $from $subject";
debugit "Speaking message from $from";
my $logmsg = "From $from $subject";
- $msg = "Message from $from... " . quotemeta $subject;
- $msg =~ s/\"/\\"/g;
+ my $msg = "Message from $from... " . quotemeta $subject;
+ $msg =~ s/\"/\\"/g;
+
+ # Log it
+ $log->msg($logmsg);
- $cmd = "/usr/local/bin/gt \"$msg\"";
+ my $cmd = "/usr/local/bin/gt \"$msg\"";
my $hour = (localtime)[2];
my $hour = (localtime)[2];
- # Only announce if after 6 Am. Not this will announce up until
+ # Only announce if after 6 Am. Note this will announce up until
# midnight but that's ok. I want midnight to 6 Am as silent time.
if ($hour > 6) {
# midnight but that's ok. I want midnight to 6 Am as silent time.
if ($hour > 6) {
- ($status, @output) = Execute $cmd;
+ my ($status, @output) = Execute $cmd;
if ($status) {
$log->err("Unable to execute $cmd" . join("\n", @output));
if ($status) {
$log->err("Unable to execute $cmd" . join("\n", @output));
-
- debugit "Sleeping for $opts{sleep} minutes";
- sleep 60 * $opts{sleep};
- debugit "Ah that was refreshing!";
} # while
return;
} # MonitorMail
} # while
return;
} # MonitorMail
-$SIG{USR2} = \&MonitorMail;
-
END {
$IMAP->quit if $IMAP;
END {
$IMAP->quit if $IMAP;
+my $msg = "Now monitoring email for $opts{username}\@$opts{imap}";
+
+$log->msg($msg);
+
+my $cmd = "/usr/local/bin/gt \"$msg\"";
+
+my ($status, @output) = Execute $cmd;
+
+$IMAP->idle(\&MonitorMail);
+