use v6.d.PREVIEW;
unit module MaildirIndexer::Parser;
use MaildirIndexer::LogTimelineSchema;
use MaildirIndexer::Email;
my @separators = (
"\x0a\x0d\x0a\x0d",
"\x0d\x0a\x0d\x0a",
"\x0a\x0a",
"\x0d\x0d",
);
my grammar Message {
regex TOP {
<headers>
<separator>
<body>
}
token newline { [\x0d\x0a] | [\x0a\x0d] | \x0a | \x0d }
token separator { @separators }
token body { .* }
regex headers {
<header>+ % <newline>
}
regex header {
<name> \: \h* <value>
|| <junk>
}
token name {
<-[:\s]>+
}
regex value {
<line>+ % [<newline> \h+]
}
token line { \N* }
token junk { \N+ }
}
my class Message-actions {
has $.path = IO;
method TOP($/) {
make MaildirIndexer::Email.new(
headers => $/<headers>.made,
body => $/<body>.Str,
path => $.path,
);
}
method headers($/) {
make %( flat |$/<header>».made );
}
method header($/) {
make $/<junk> ?? () !! ( $/<name>.Str.lc => $/<value>.made );
}
method value($/) {
make $/<line>.join(' ')
}
}
multi parse-email(IO::Path:D $p --> MaildirIndexer::Email) is export {
my MaildirIndexer::Email $result;
MaildirIndexer::LogTimelineSchema::Parse::Email::File.log: :file($p.path), -> {
$result = parse-email($p.slurp(:enc<utf8-c8>), path => $p);
}
return $result;
}
multi parse-email(IO::Path:D $p, :$headers-only! --> MaildirIndexer::Email) is export {
my MaildirIndexer::Email $result;
MaildirIndexer::LogTimelineSchema::Parse::Email::File.log: :file($p.path), -> {
$result = parse-email(
$p.lines(
:enc<utf8-c8>,
:nl-in(@separators),
:!chomp,
)[0],
path => $p,
);
}
return $result;
}
multi parse-email(IO::Socket::Async:D $s --> MaildirIndexer::Email) is export {
my MaildirIndexer::Email $result;
MaildirIndexer::LogTimelineSchema::Parse::Email::Socket.log: -> {
my $string;
react {
whenever $s.Supply(:enc<utf8-c8>) {
$string ~= $_;
$result = parse-email($string) and done;
}
}
}
return $result;
}
multi parse-email(Str:D $email-str, :$path = IO --> MaildirIndexer::Email) is export {
my MaildirIndexer::Email $result;
MaildirIndexer::LogTimelineSchema::Parse::Email::Str.log: -> {
CATCH { warn .perl; return Nil };
with Message.parse($email-str,:actions(Message-actions.new(:$path))) {
$result = .made;
}
}
return $result;
}