From 50a37d8812c95c60203b0102db91f0c080d4d93b Mon Sep 17 00:00:00 2001 From: Florian Pritz Date: Tue, 17 Jul 2018 15:26:40 +0200 Subject: Initial port of single file script Signed-off-by: Florian Pritz --- lib/App/ImapNotify.pm | 95 ++++++++++++++++- lib/App/ImapNotify/ImapClient.pm | 214 +++++++++++++++++++++++++++++++++++++++ lib/App/ImapNotify/Notifier.pm | 48 +++++++++ lib/App/ImapNotify/Socket/SSL.pm | 34 +++++++ 4 files changed, 386 insertions(+), 5 deletions(-) create mode 100644 lib/App/ImapNotify/ImapClient.pm create mode 100644 lib/App/ImapNotify/Notifier.pm create mode 100644 lib/App/ImapNotify/Socket/SSL.pm (limited to 'lib') diff --git a/lib/App/ImapNotify.pm b/lib/App/ImapNotify.pm index 4cf5354..0b44f68 100644 --- a/lib/App/ImapNotify.pm +++ b/lib/App/ImapNotify.pm @@ -1,14 +1,16 @@ package App::ImapNotify; -use 5.008001; +use v5.24; use strict; use warnings; our $VERSION = "0.01"; +use App::ImapNotify::ImapClient; +use App::ImapNotify::Notifier; - -1; -__END__ +use Carp; +use Function::Parameters; +use Log::Any qw($log); =encoding utf-8 @@ -22,7 +24,9 @@ App::ImapNotify - It's new $module =head1 DESCRIPTION -App::ImapNotify is ... +App::ImapNotify is a simple notification script using IMAP NOTIFY. Note that it is very simple and +implements a custom IMAP client with very limited features. Mostly a proof of +concept and personal script. =head1 LICENSE @@ -37,3 +41,84 @@ Florian Pritz Ebluewind@xinu.atE =cut +method new($class: $config, $deps = {}) { + $deps->{imap_client} //= App::ImapNotify::ImapClient->new({$config->%{qw(host port log_id username password keepalive_timeout)}}); + $deps->{notifier} //= App::ImapNotify::Notifier->new(); + return $class->new_no_defaults($config, $deps); +} + +method new_no_defaults($class: $config, $deps = {}) { + my $self = {}; + bless $self, $class; + $self->{config} = $config; + $self->{deps} = $deps; + return $self; +} + +method loop() { + #my $imap = $self->{deps}->{imap_client}->connect($self->{config}->@{qw(host port log_id)}); + #$imap->login($self->{config}->@{qw(username password)}); + my $imap = $self->{deps}->{imap_client}; + $imap->select($self->{config}->{mailboxes}->@[0]); + + $imap->send_command("notify set (selected (MessageExpunge MessageNew (uid body.peek[header.fields (from to subject)]))) (mailboxes (".join(' ', $self->{config}->{mailboxes}->@*).") (MessageNew MessageExpunge MailboxName))"); + + $log->info("Waiting for notify events"); + while (my $line = $imap->readline_timeout()) { + $log->tracef("Got line: '%s'", $line); + if ($line =~ m/^\* .* FETCH /) { + my $message = $imap->handle_fetch($line); + $self->_notify($message); + next; + } + if ($line =~ m/^\* STATUS (?[^ ]+) \(MESSAGES \d+ UIDNEXT (?\d+) UNSEEN \d+\)/) { + $log->debugf("Got status change: '%s'", $line); + my $mailbox = $+{mailbox}; + my $uid = $+{uidnext} - 1; + #$imap2->select($mailbox); + #my $message = $imap2->send_command("uid fetch $uid (body.peek[header.fields (from to subject)])"); + $imap->select($mailbox); + my $message = $imap->send_command("uid fetch $uid (body.peek[header.fields (from to subject)])"); + pop @{$message}; + $self->_notify($message); + next; + } + + next if $line =~ /\* \d+ RECENT/; + next if $line =~ /\* \d+ EXISTS/; + next if $line =~ /\* \d+ EXPUNGE/; + + confess(sprintf("Got unexpected line: '%s'", $line)); + } +} + +method _notify($message) { + $log->debugf("Got data for notification: %s", $message); + my $fields = {}; + my $current_field; + + return if $message->@* == 0; + + for my $line ($message->@*) { + if ($line =~ m/^(?