# GotMArc was written by Omar Polo and is placed in # the public domain. The author hereby disclaims copyright to this # source code. package SMArc; use strict; use warnings; use v5.32; use Exporter; use File::Basename; our @ISA = qw(Exporter); our @EXPORT_OK = qw(san urlencode parse initpage endpage index_header search thread_header threntry thrslice thrnav); sub san { my $str = shift; $str =~ s/&/\&/g; $str =~ s//\>/g; return $str; } sub urlencode { my $str = shift; unless (defined($str)) { my ($pkg, $file, $line) = caller 1; die "bad $pkg / $file:$line"; } $str =~ s/([^-_~.A-Za-z0-9])/sprintf("%%%2X", ord($1))/ge; return $str; } sub ssan { my $str = shift; $str =~ s/\s+/ /g; $str =~ s/\s+$//; return san($str); } sub parse { my $line = shift; my ($indent, $fname, $date, $from, $subj) = $line =~ m{ ^([^-]*)- # the indent level ([^ ]+)\s # filename (\d{4}-\d\d-\d\d[ ]\d\d:\d\d) # date <([^>]+)> # from (.*) # subject }x or die "can't parse: $line"; my $level = length($indent); $level = 10 if $indent =~ m/\.\.\d+\.\./; $from = ssan($from); $subj = ssan($subj); my ($time, $id) = split /\./, basename($fname); my $mid = "$time.$id"; return {level => $level, fname => $fname, mid => $mid, date => $date, from => $from, subj => $subj}; } sub readall { my $path = shift; local $/ = undef; open my $fh, "<", $path or die "can't open $path: $!"; <$fh>; } my $templates = $ENV{TMPLDIR}; die 'undefined $TMPLDIR' unless defined $templates; my $small_logo = readall "$templates/logo-small.html"; my $hdr = readall "$templates/head.html"; my $foot = readall "$templates/foot.html"; my $idxhdr = readall "$templates/index-header.html"; my $search = readall "$templates/search.html"; sub initpage { my ($fh, $title) = @_; say $fh $hdr =~ s/TITLE/$title/r; } sub endpage { my $fh = shift; say $fh $foot; } sub index_header { my ($fh, $page, $subtitle) = @_; my $html = $idxhdr =~ s/PAGE/$page/r; $html =~ s/SUBTITLE/$subtitle/; print $fh $html; } sub search { my $fh = shift; my $html = $search =~ s/QUERY//r; print $fh $html; } sub thread_header { my ($fh, $e, $mail, $p, $n) = @_; my @entries = @$e; my $enctid = urlencode $mail->{tid} if defined $mail; my $encmid = urlencode $mail->{mid} if defined $mail; print $fh "
\n"; print $fh "

"; print $fh $small_logo; print $fh "Index"; print $fh " | Thread" if defined $enctid; print $fh " | Search"; print $fh "

\n"; say $fh "
"; foreach my $entry (@entries) { my ($k, $v) = split /: /, $entry, 2; chomp $v; say $fh "
$k:
$v
"; } say $fh "
"; say $fh "

Download raw body.

" if defined $encmid; if (defined($p) and defined($n)) { say $fh "
"; say $fh "Thread"; thrslice($fh, $mail, $p, $n); say $fh "
"; thrnav($fh, $p, $n, $mail->{mid}, $mail->{tid}); } say $fh "
\n"; } sub threntry { my ($fh, $type, $base, $last_level, $mail, $cur) = @_; my $level = $mail->{level} - $base; say $fh "" x ($last_level - $level) if $last_level > $level; say $fh "
  • "; } sub thrnav { my ($fh, $p, $n) = @_; my @prev = @{$p}; my @next = @{$n}; return if !@prev && !@next; print $fh ""; } 1;