about summary refs log tree commit diff homepage
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--_css/style.css11
-rw-r--r--_layout/page_foot.html12
-rw-r--r--_libs/formbox/comment.html7
-rw-r--r--_libs/formbox/comment.xml1
-rwxr-xr-x_libs/formbox/format71
-rw-r--r--_rss/comments.xml11
-rw-r--r--_rss/head.xml4
-rw-r--r--_rss/item.xml6
-rw-r--r--index.md2
-rw-r--r--utils.jl24
11 files changed, 125 insertions, 25 deletions
diff --git a/.gitignore b/.gitignore
index 2355507..0a3ca5a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@ __site/
 _css/fonts/
 _css/katex.min.css
 _libs/fediring
+_libs/formbox/mbox
 _libs/highlight/
 _libs/katex/
 _libs/openring/out.html
diff --git a/_css/style.css b/_css/style.css
index 790c177..af502d7 100644
--- a/_css/style.css
+++ b/_css/style.css
@@ -204,7 +204,7 @@ code, .hljs {
     padding: 0.1em 0.2em;
 }
 
-.hljs {
+.hljs, .comment pre > code {
     display: block;
     line-height: 1.45em;
     overflow-x: auto;
@@ -227,6 +227,15 @@ code, .hljs {
 .hljs-selector-pseudo, .hljs-template-tag, .hljs-template-variable,
 .hljs-addition { color: var(--red) }
 
+.comment {
+    background-color: #8881;
+    clear: both;
+    margin: 1ex 0;
+    overflow: hidden;
+    padding: 1ex;
+}
+.comment p { margin: 1ex }
+
 .openring {
     display: flex;
     flex-wrap: wrap;
diff --git a/_layout/page_foot.html b/_layout/page_foot.html
index 848d42e..88d33ea 100644
--- a/_layout/page_foot.html
+++ b/_layout/page_foot.html
@@ -1,11 +1,11 @@
 {{isnotempty tags}}<small class=tags><strong>Tags:</strong>{{for tag in tags}}
   <a href=/tag/{{tag}}>{{tag}}</a>{{end}}</small>
 <small class=right>&mdash;{{isempty rss}}{{author}},
-  {{else}}{{mailto_comment}}, {{end}}{{date}}</small><br>{{end}}
+  {{else}}<a href="{{mailto_comment}}" title="Reply via email">{{author}}</a>,
+  {{end}}{{date}}</small><br>{{end}}
 
-{{isnotempty rss}}<section class=comments>
-  <h2>Comments</h2>
-  <p>To reply, follow the <code>mailto</code> link
-    in the the author's name.</p>
-</section>{{end}}
+{{isnotempty rss}}<h2>Comments</h2>
+{{comments_rendered}}
+<p>To reply, follow the <code>mailto</code> link
+  in the the author's name.</p>{{end}}
 {{insert footer.html}}
diff --git a/_libs/formbox/comment.html b/_libs/formbox/comment.html
new file mode 100644
index 0000000..60459d9
--- /dev/null
+++ b/_libs/formbox/comment.html
@@ -0,0 +1,7 @@
+<div class=comment>
+  {body}
+  <p class=right>&mdash;{author},
+    <a href="https://lists.sr.ht/~cnx/site/{message_id}"
+       title="View source">{date}</a></p>
+  {children}
+</div>
diff --git a/_libs/formbox/comment.xml b/_libs/formbox/comment.xml
index 2078071..5f183a0 100644
--- a/_libs/formbox/comment.xml
+++ b/_libs/formbox/comment.xml
@@ -4,7 +4,6 @@
   <pubDate>{date}</pubDate>
   <dc:creator>{author}</dc:creator>
   <title>On {date}, {author} wrote:</title>
-  <description>{subject}</description>
   <content:encoded><![CDATA[{body}]]></content:encoded>
 </item>
 {children}
diff --git a/_libs/formbox/format b/_libs/formbox/format
new file mode 100755
index 0000000..39e6132
--- /dev/null
+++ b/_libs/formbox/format
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+# Format mbox as HTML/XML
+# Copyright (C) 2021  Nguyễn Gia Phong
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+from argparse import ArgumentParser
+from email.header import decode_header
+from email.utils import parsedate_to_datetime
+from functools import partial
+from itertools import starmap
+from mailbox import mbox
+from pathlib import Path
+from urllib.parse import quote
+
+from bleach import clean, linkify
+from markdown import markdown
+
+sanitise = partial(clean, tags=('a', 'code', 'em', 'strong', 'sub', 'sup',
+                                'blockquote', 'p', 'pre', 'ul', 'ol', 'li'),
+                   protocols=('ftp', 'gemini', 'gopher', 'http', 'https',
+                              'irc', 'ircs', 'mailto', 'matrix', 'xmpp'))
+
+
+def extract(archive, parent):
+    for message_id, message in archive.copy().items():
+        # TODO: handle multipart
+        if message['In-Reply-To'] != parent: continue
+        archive.pop(message_id)
+        yield message, extract(archive, message_id)
+
+
+def decode(header):
+    for string, charset in decode_header(header):
+        encoding = 'utf-8' if charset is None else charset
+        yield string.decode(encoding)
+
+
+def render(template, forest, parent):
+    for self, children in forest:
+        message_id = self['Message-Id']
+        date = parsedate_to_datetime(self['Date']).date().isoformat()
+        author, address = decode(self['From'])
+        body = sanitise(linkify(markdown(self.get_payload(),
+                                         output_format='html5')))
+        rendered_children = render(template, children, message_id)
+        yield template.format(message_id=quote(message_id),
+                              date=date, author=author, body=body,
+                              children='\n'.join(rendered_children))
+
+
+parser = ArgumentParser()
+parser.add_argument('mbox')
+parser.add_argument('id')
+parser.add_argument('template', type=Path)
+args = parser.parse_args()
+
+archive = {m['Message-Id']: m for m in mbox(args.mbox)}
+template = args.template.read_text()
+print(*render(template, extract(archive, args.id), args.id), sep='', end='')
diff --git a/_rss/comments.xml b/_rss/comments.xml
index be8fa6c..13d514b 100644
--- a/_rss/comments.xml
+++ b/_rss/comments.xml
@@ -4,7 +4,14 @@
      xmlns:content="http://purl.org/rss/1.0/modules/content"
      xmlns:dc="http://purl.org/dc/elements/1.1">
 <channel>
-<title>Comments on {{fd2rss rss_title}}</title>
+<title>Re: {{fd2rss rss_title}}</title>
 <link>{{fd_full_url}}</link>
-<description></description>
+<atom:link href="{{comment_rss_feed_url}}"
+           rel="self"
+           type="application/rss+xml"/>
+<description>Comments on {{fd2rss rss_title}}</description>
+<language>en</language>
 <generator>Formbox</generator>
+{{comment_rss_items}}
+</channel>
+</rss>
diff --git a/_rss/head.xml b/_rss/head.xml
index 929038f..e27fe5e 100644
--- a/_rss/head.xml
+++ b/_rss/head.xml
@@ -6,9 +6,7 @@
 <channel>
 <title>{{website_title}}</title>
 <link>{{website_url}}</link>
-<atom:link href="{{fd_rss_feed_url}}"
-           rel="self"
-           type="application/rss+xml"/>
+<atom:link href="{{fd_rss_feed_url}}" rel="self" type="application/rss+xml"/>
 <description>{{website_description}}</description>
 <copyright><![CDATA[{{copyright}} under CC BY-SA 4.0]]></copyright>
 <language>en</language>
diff --git a/_rss/item.xml b/_rss/item.xml
index 76f892a..8a808ff 100644
--- a/_rss/item.xml
+++ b/_rss/item.xml
@@ -5,10 +5,8 @@
   <description>{{fd2rss rss_description}}</description>
   {{for tag in tags}}<category>{{tag}}</category>{{end}}
   <pubDate>{{RFC822 rss_pubdate}}</pubDate>
-  <content:encoded>
-    <![CDATA[{{fix_relative_links fd_page_html}}
-    <a href="{{mailto_comment}}">Reply</a>]]>
-  </content:encoded>
+  <content:encoded><![CDATA[{{fix_relative_links fd_page_html}}
+    <a href="{{mailto_comment}}">Reply via email</a>]]></content:encoded>
   <comments><![CDATA[{{comments}}]]></comments>
   <wfw:commentRss>{{comment_rss}}</wfw:commentRss>
 </item>
diff --git a/index.md b/index.md
index d360f1d..1c1166b 100644
--- a/index.md
+++ b/index.md
@@ -15,7 +15,7 @@ in the [Fediverse][]:
 * Matrix: [@cnx:halogen.city]
 
 [^culture]: Not necessarily mutually exclusive
-[^xmpp]: Also XMPP, but mostly inactive
+[^xmpp]: Or XMPP where I'm rarely active
 [^pgp]: PGP: [27148B2C06A2224B], also on [OpenPGP]
 
 [My name is]: https://www.youtube.com/watch?v=LDj8kkVwisY
diff --git a/utils.jl b/utils.jl
index 5a6e1c4..81c56fa 100644
--- a/utils.jl
+++ b/utils.jl
@@ -11,19 +11,32 @@ function hfun_abslink(args)
 end
 
 dir_url() = strip(dirname(locvar(:fd_url)), '/')
-message_id() = @sprintf("<%s@cnx>", dir_url())
+message_id() = "<$(dir_url())@cnx>"
 hfun_comments() = @sprintf("https://lists.sr.ht/~cnx/site?search=%s:%s",
                            "In-Reply-To", message_id())
 
+function render_comments(template)
+  prefix = joinpath(path(:libs), "formbox")
+  format = joinpath(prefix, "format")
+  mbox = joinpath(prefix, "mbox")
+  template_path = joinpath(prefix, template)
+  readchomp(`python3 $format $mbox $(message_id()) $template_path`)
+end
+
+hfun_comments_rendered() = render_comments("comment.html")
+
 function hfun_comment_rss()
   rpath = joinpath(dir_url(), "comments.xml")
   open(joinpath(path(:site), rpath), "w") do feed
     write(feed, convert_html(readchomp(joinpath(path(:rss), "comments.xml"))))
-    #write(feed, read(`python3 formbox.py mbox $(message_id()) $item_template`, String))
   end
   joinpath(globvar(:website_url), rpath)
 end
 
+hfun_comment_rss_feed_url() = joinpath(dirname(locvar(:fd_full_url)),
+                                       "comments.xml")
+hfun_comment_rss_items() = render_comments("comment.xml")
+
 function hfun_fediring(args)
   adj = readlines(joinpath(path(:libs), "fediring"))[parse(Int, args[1])]
   "<a href=https://$adj>$(args[2])</a>"
@@ -33,11 +46,8 @@ hfun_github(args) = "<a href=https://github.com/$(args[1])>@$(args[1])</a>"
 hfun_job_url() = get(ENV, "JOB_URL", "https://builds.sr.ht/~cnx/site")
 
 function hfun_mailto_comment()
-  @sprintf("<a href='mailto:%s?%s=%s&%s=Re: %s' title='Reply via email'>%s</a>",
-           "~cnx/site@lists.sr.ht",
-           "In-Reply-To", message_id(),
-           "Subject", locvar(:title),
-           globvar(:author))
+  @sprintf("mailto:%s?%s=%s&%s=Re: %s", "~cnx/site@lists.sr.ht",
+           "In-Reply-To", message_id(), "Subject", locvar(:title))
 end
 
 hfun_openring() = readchomp(joinpath(path(:libs), "openring", "out.html"))