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 --- META.json | 11 +- README.md | 4 +- cpanfile | 18 +++- lib/App/ImapNotify.pm | 95 ++++++++++++++++- lib/App/ImapNotify/ImapClient.pm | 214 +++++++++++++++++++++++++++++++++++++++ lib/App/ImapNotify/Notifier.pm | 48 +++++++++ lib/App/ImapNotify/Socket/SSL.pm | 34 +++++++ script/imap-notify.pl | 58 +++++++++++ t/00_compile.t | 4 + t/01_basic.t | 58 +++++++++++ t/02_noop.t | 73 +++++++++++++ 11 files changed, 607 insertions(+), 10 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 create mode 100755 script/imap-notify.pl create mode 100644 t/01_basic.t create mode 100644 t/02_noop.t diff --git a/META.json b/META.json index 4350f14..0f03234 100644 --- a/META.json +++ b/META.json @@ -42,11 +42,20 @@ }, "runtime" : { "requires" : { - "perl" : "5.008001" + "Function::Parameters" : "0", + "IO::Socket::SSL" : "0", + "Log::Any" : "0", + "Log::Any::Adapter" : "0", + "MCE::Hobo" : "0", + "Time::Out" : "0", + "autodie" : "0", + "perl" : "v5.24.0" } }, "test" : { "requires" : { + "Test::Differences" : "0", + "Test::MockObject" : "0", "Test::More" : "0.98" } } diff --git a/README.md b/README.md index 7849029..6de1231 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,9 @@ App::ImapNotify - It's new $module # 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. # LICENSE diff --git a/cpanfile b/cpanfile index 3f15d5e..5f314dd 100644 --- a/cpanfile +++ b/cpanfile @@ -1,6 +1,18 @@ -requires 'perl', '5.008001'; +requires 'Function::Parameters'; +requires 'IO::Socket::SSL'; +requires 'Log::Any'; +requires 'Log::Any::Adapter'; +requires 'MCE::Hobo'; +requires 'Time::Out'; +requires 'autodie'; +requires 'perl', 'v5.24.0'; -on 'test' => sub { - requires 'Test::More', '0.98'; +on configure => sub { + requires 'Module::Build::Tiny', '0.035'; }; +on test => sub { + requires 'Test::Differences'; + requires 'Test::MockObject'; + requires 'Test::More', '0.98'; +}; 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/^(?