# Copyright (C) 2020 all contributors
# License: AGPL-3.0+
# Writes PublicInbox::Eml objects atomically to a mbox variant or Maildir
package PublicInbox::LeiToMail;
use strict;
use v5.10.1;
use PublicInbox::Eml;
my %kw2char = ( # Maildir characters
draft => 'D',
flagged => 'F',
answered => 'R',
seen => 'S'
);
my %kw2status = (
flagged => [ 'X-Status' => 'F' ],
answered => [ 'X-Status' => 'A' ],
seen => [ 'Status' => 'R' ],
draft => [ 'X-Status' => 'T' ],
);
sub _mbox_hdr_buf ($$$) {
my ($eml, $type, $kw) = @_;
$eml->header_set($_) for (qw(Lines Bytes Content-Length));
my %hdr; # set Status, X-Status
for my $k (@$kw) {
if (my $ent = $kw2status{$k}) {
push @{$hdr{$ent->[0]}}, $ent->[1];
} else { # X-Label?
warn "TODO: keyword `$k' not supported for mbox\n";
}
}
while (my ($name, $chars) = each %hdr) {
$eml->header_set($name, join('', sort @$chars));
}
my $buf = delete $eml->{hdr};
# fixup old bug from import (pre-a0c07cba0e5d8b6a)
$$buf =~ s/\A[\r\n]*From [^\r\n]*\r?\n//s;
substr($$buf, 0, 0, # prepend From line
"From lei\@$type Thu Jan 1 00:00:00 1970$eml->{crlf}");
$buf;
}
sub write_in_full_atomic ($$) {
my ($fh, $buf) = @_;
defined(my $w = syswrite($fh, $$buf)) or die "write: $!";
$w == length($$buf) or die "short write: $w != ".length($$buf);
}
sub eml2mboxrd ($;$) {
my ($eml, $kw) = @_;
my $buf = _mbox_hdr_buf($eml, 'mboxrd', $kw);
if (my $bdy = delete $eml->{bdy}) {
$$bdy =~ s/^(>*From )/>$1/gm;
$$buf .= $eml->{crlf};
substr($$bdy, 0, 0, $$buf); # prepend header
$buf = $bdy;
}
$$buf .= $eml->{crlf};
$buf;
}
sub eml2mboxo {
my ($eml, $kw) = @_;
my $buf = _mbox_hdr_buf($eml, 'mboxo', $kw);
if (my $bdy = delete $eml->{bdy}) {
$$bdy =~ s/^From />From /gm;
$$buf .= $eml->{crlf};
substr($$bdy, 0, 0, $$buf); # prepend header
$buf = $bdy;
}
$$buf .= $eml->{crlf};
$buf;
}
# mboxcl still escapes "From " lines
sub eml2mboxcl {
my ($eml, $kw) = @_;
my $buf = _mbox_hdr_buf($eml, 'mboxcl', $kw);
my $crlf = $eml->{crlf};
if (my $bdy = delete $eml->{bdy}) {
$$bdy =~ s/^From />From /gm;
$$buf .= 'Content-Length: '.length($$bdy).$crlf.$crlf;
substr($$bdy, 0, 0, $$buf); # prepend header
$buf = $bdy;
}
$$buf .= $crlf;
$buf;
}
# mboxcl2 has no "From " escaping
sub eml2mboxcl2 {
my ($eml, $kw) = @_;
my $buf = _mbox_hdr_buf($eml, 'mboxcl2', $kw);
my $crlf = $eml->{crlf};
if (my $bdy = delete $eml->{bdy}) {
$$buf .= 'Content-Length: '.length($$bdy).$crlf.$crlf;
substr($$bdy, 0, 0, $$buf); # prepend header
$buf = $bdy;
}
$$buf .= $crlf;
$buf;
}
1;