commit 7d6d378a8d77a583c9b79f8ade1900108b773788 from: Omar Polo date: Wed Aug 24 09:11:58 2022 UTC initial import commit - /dev/null commit + 7d6d378a8d77a583c9b79f8ade1900108b773788 blob - /dev/null blob + 0fe0a0f5dfb51bcd82a1f0fde0cea7aaecf82cc7 (mode 644) --- /dev/null +++ Makefile @@ -0,0 +1,31 @@ +ENV = MBLAZE=.mblaze OUTDIR='${OUTDIR}' +MBLAZE_PAGER = cat +MDIR = ${HOME}/Maildir/op/GoT +OUTDIR = www + +.PHONY: all dirs assets clean + +all: .mblaze dirs assets + mlist '${MDIR}' | mthread -r | \ + ${ENV} mscan -f '%R %I %i %16D <%16f> %128S' | \ + ${ENV} ./mexp | ${ENV} ./mkindex > ${OUTDIR}/index.html + +dirs: + mkdir -p ${OUTDIR}/thread/ + +assets: dirs got.png style.css + cp got.png ${OUTDIR}/got@2x.png + convert got.png -resize 200x200 ${OUTDIR}/got.png + convert got.png -resize 128x128 ${OUTDIR}/got-tiny@2x.png + convert got.png -resize 64x64 ${OUTDIR}/got-tiny.png + cp style.css ${OUTDIR} + +${OUTDIR}: + mkdir -p '${OUTDIR}' + +.mblaze: + mkdir -p .mblaze + touch .mblaze/seq + +clean: + rm -rf ${OUTDIR} blob - /dev/null blob + bb76eb365659ca981bba169a4fcb5354902be754 (mode 644) --- /dev/null +++ foot.html @@ -0,0 +1,18 @@ + + + blob - /dev/null blob + 8fbd066279db65e381ce8a21be95c58ac4dfc788 (mode 644) Binary files /dev/null and got.png differ blob - /dev/null blob + 645e87d154d795011826359bae74da233dc7a8d7 (mode 644) --- /dev/null +++ head.html @@ -0,0 +1,9 @@ + + + + + + + TITLE + + blob - /dev/null blob + ccd0aa94dcae27fdcdb7804e350487f62f70580b (mode 755) --- /dev/null +++ mexp @@ -0,0 +1,111 @@ +#!/usr/bin/env perl + +use open ":std", ":encoding(UTF-8)"; +use utf8; +use strict; +use warnings; +use v5.32; + +my $outdir = $ENV{'OUTDIR'}; +die 'Set $OUTDIR' unless defined $outdir; +mkdir $outdir; + +my $hdr = do { + local $/ = undef; + open my $fh, "<", "head.html" + or die "can't open head.html: $!"; + <$fh>; +}; + +my $foot = do { + local $/ = undef; + open my $fh, "<", "foot.html" + or die "can't open foot.html: $!"; + <$fh>; +}; + +my $logo = < +EOF + +sub san { + my $str = shift; + $str =~ s/&/\&/g; + $str =~ s//\>/g; + return $str; +} + +my $tid; +while (<>) { + chomp; + say; # continue the pipeline + + m/^([^ ]+) <([^>]+)> (.+)(\d{4}-\d{2}-\d{2} \d{2}:\d{2}) <([^>]+)> (.*)/; + die "can't parse: $_" unless defined $1; + my ($fname, $mid, $indent, $date, $from, $subj) = ($1, $2, $3, $4, $5, $6); + $subj = san($subj); + $subj =~ s/\s+/ /g; + $subj =~ s/\s+$//; + + $mid =~ s,_,__,g; + $mid =~ s,/,_,g; + + chomp($mid); + + next if -f "$outdir/$mid.html"; + + my $level = length($indent) - 1; + $level = 10 if $indent =~ m/\.\.\d{2}\.\./; + + $tid = $mid if $level == 0; + + my $dest = "$outdir/$mid.html"; + open(my $fh, '>', "$dest") or die "can't open $dest: $!"; + + say $fh $hdr =~ s/TITLE/$subj/r; + + open(my $mshow, "-|", "mshow", "-nNA", "text/plain", $fname) + or die "can't exec mshow: $!"; + + print $fh "
"; + print $fh "

"; + print $fh $logo; + print $fh "‹ Back to the index"; + print $fh " or "; + print $fh "→ go to the thread."; + print $fh "

"; + print $fh "
"; + while (<$mshow>) { + chomp; + last if /^$/; + my ($h, $v) = m/^([-A-Za-z]+): (.*)/; + die "bogus line? $fname : $_" unless (defined $h and defined $v); + + # drop the (1 day ago) string + $v =~ s/\(.*\)//g if ($h eq "Date"); + + print $fh "
", san($h), ":
"; + print $fh "
", san($v), "
"; + } + print $fh "
"; + + my $body = do { + local $/ = undef; + <$mshow>; + }; + + print $fh "
";
+	# print $fh san($_) while <>;
+	print $fh san($body // "");
+	print $fh "
"; + + print $fh $foot; + + close($mshow); + close($fh); + + # exit(0); +} blob - /dev/null blob + 725f605f6ba88ebd61e5d2a49f24619b9d8f258f (mode 755) --- /dev/null +++ mkindex @@ -0,0 +1,145 @@ +#!/usr/bin/env perl + +use open ":std", ":encoding(UTF-8)"; +use utf8; +use strict; +use warnings; +use v5.32; + +my $outdir = $ENV{'OUTDIR'}; +die 'Set $OUTDIR' unless defined $outdir; +mkdir $outdir; + +my $tfh; + +my $logo = < +EOF + +sub san { + my $str = shift; + $str =~ s/&/\&/g; + $str =~ s//\>/g; + return $str; +} + +sub initpage { + my ($fh, $title) = @_; + open(my $hdr, '<', 'head.html') + or die "can't open head.html: $!"; + while (<$hdr>) { + s/TITLE/$title/; + print $fh $_; + } +} + +sub endpage { + my $fh = shift; + open(my $foot, '<', 'foot.html') + or die "can't open foot.html: $!"; + print $fh $_ while <$foot>; +} + +sub nextthread { + endthread() if defined($tfh); + my ($mid, $subj) = @_; + my $dest = "$outdir/thread/$mid.html"; + open($tfh, '>', $dest) or die "can't open $dest: $!"; + initpage($tfh, $subj); + + print $tfh "
"; + print $tfh "

"; + print $tfh $logo; + print $tfh "‹ Back to the index"; + print $tfh "

"; + print $tfh "
Thread:
$subj
"; + print $tfh "
\n"; + print $tfh "
\n"; +} + +sub endthread { + print $tfh "
\n"; + endpage($tfh); + close($tfh); +} + +sub entry_raw { + my ($fh, $mid, $level, $date, $from, $subj) = @_; + + my $class = ""; + $class = "reply indent-$level" unless $level == 0; + print $fh "
"; + print $fh "

"; + print $fh " "; + print $fh "$from"; + print $fh ":"; + if ($fh != $tfh && $level == 0) { + print $fh " (thread)"; + } + print $fh "

"; + print $fh "

"; + print $fh "$subj"; + print $fh "

"; + print $fh "
\n"; +} + +sub entry { + entry_raw(\*STDOUT, @_); + entry_raw($tfh, @_); +} + +initpage(\*STDOUT, "Game of Trees Mail Archive"); +print < + + "GOT" where the "O" is a cute smiling sun. + +

Game of Trees Mail Archive

+ +
+EOF + +my $threads_seen = 0; +while (<>) { + chomp; + m/^[^ ]+ <([^>]+)> (.+)(\d{4}-\d{2}-\d{2} \d{2}:\d{2}) <([^>]+)> (.*)/; + die "woops; $_\n" unless defined $1; + + my ($mid, $indent, $date, $from, $subj) = ($1, $2, $3, $4, $5); + $from =~ s/\s+$//; + $from = san($from); + $subj = san($subj); + + my $level = length($indent) - 1; + $level = 10 if $indent =~ m/\.\.\d{2}\.\./; + + $mid =~ s,_,__,g; + $mid =~ s,/,_,g; + + $subj =~ s/\s+/ /g; + $subj =~ s/\s+$//g; + + my $new_thread = $indent eq " "; + say "
" if $threads_seen && $new_thread; + if ($new_thread) { + nextthread($mid, $subj); + say "
"; + } + + $threads_seen = 1; + + entry($mid, $level, $date, $from, $subj); +} + +if ($threads_seen) { + say "
" ; + endthread(); +} + +say "
"; +endpage(\*STDOUT); blob - /dev/null blob + 1fa1d9e9083db98c0fbfa60c84b44f5b7d78c50d (mode 644) --- /dev/null +++ style.css @@ -0,0 +1,133 @@ +* { + box-sizing: border-box; +} + +body { + margin: 0; + padding: 0; + border: 0; + font: 14px sans-serif; +} + +header.mail-header { + background-color: #ced7e0; + padding: 5px 10px; + margin: 10px 0; +} + +header.mail-header img { + vertical-align: middle; +} + +header dl { + display: flex; + flex-wrap: wrap; + margin: 0; +} + +header dt { + width: 70px; +} + +header dd { + margin-left: auto; + width: calc(100% - 70px); + flex-grow: 2; +} + +header dt, header dd { + padding: 3px 0; +} + +header.index-header { + margin: 20px 0; + text-align: center; +} + +h1 { + font-weight: normal; + font-size: 1.8rem; + margin: 0 0 1rem 0; +} + +main { + padding: 5px; +} + +pre { + font-family: monospace; + padding: 5px; + white-space: pre-wrap; +} + +hr { + display: none; +} + +.thread { + margin: 2rem 0; +} + +.thread p { + margin: 0; +} + +.thread a { + text-decoration: none; +} + +.thread a:hover { + text-decoration: underline; +} + +.mail { + /* font-family: monospace; */ + margin: 0.5rem 0; + /* display: flex; */ + /* flex-direction: row; */ +} + +.mail:target { + background-color: khaki; +} + +.mail .mail-meta { + font-size: 13px; +} + +.mail.reply .subject { + overflow: hidden; + text-overflow: ellipsis; + white-space: pre; +} + +.mail.indent-1 { padding-left: 10px; } +.mail.indent-2 { padding-left: 20px; } +.mail.indent-3 { padding-left: 30px; } +.mail.indent-4 { padding-left: 40px; } +.mail.indent-5 { padding-left: 50px; } +.mail.indent-6 { padding-left: 60px; } +.mail.indent-7 { padding-left: 70px; } +.mail.indent-8 { padding-left: 80px; } +.mail.indent-9 { padding-left: 90px; } +.mail.indent-10 { padding-left: 100px; } + + +footer { + margin-top: 70px; + border-top: 1px solid black; +} + +footer > p { + text-align: center; +} + +footer ul { + padding: 0; + text-align: center; +} + +footer li { + display: inline-block; + padding: 8px; +}