Description: add various tools to help slidge-based XMPP gateway development
 Source: https://codeberg.org/slidge/sphinx-extensions
Author: Nicolas Cedilnik <nicoco@nicoco.fr>, Martin <debacle@debian.org>
Origin: vendor
Bug-Debian: https://bugs.debian.org/1057869
Last-Update: 2025-01-22
---
This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
--- /dev/null
+++ b/slidge_sphinx_extensions/config_obj.py
@@ -0,0 +1,74 @@
+import importlib
+from typing import get_type_hints
+
+from docutils import nodes
+from sphinx.util.docutils import SphinxDirective
+from sphinx.util.logging import getLogger
+
+
+def valid_option(name: str):
+    return (
+        not name.startswith("_")
+        and not name.endswith("__DOC")
+        and name.upper() == name
+        and not name.endswith("__DYNAMIC_DEFAULT")
+    )
+
+
+class ConfigObj(SphinxDirective):
+    has_content = True
+
+    def run(self):
+        module = importlib.import_module(self.content[0])
+
+        table = nodes.table()
+        tgroup = nodes.tgroup()
+
+        colspec = nodes.colspec()
+
+        tgroup += colspec
+        tgroup += colspec
+        tgroup += colspec
+
+        table += tgroup
+
+        tbody = nodes.tbody()
+
+        params = [name for name in dir(module) if valid_option(name)]
+
+        # options without default values
+        for name, _ in get_type_hints(module).items():
+            if not valid_option(name):
+                continue
+            if name not in params:
+                params.append(name)
+
+        for param in params:
+            row = nodes.row()
+
+            entry = nodes.entry()
+            entry.append(nodes.Text(param))
+            row += entry
+
+            entry = nodes.entry()
+            entry.append(nodes.Text(getattr(module, param + "__DOC")))
+            row += entry
+
+            tbody += row
+
+        tgroup += tbody
+
+        return [table]
+
+
+def setup(app):
+    app.add_directive("config-obj", ConfigObj)
+
+    return {
+        "version": "0.1",
+        "parallel_read_safe": True,
+        "parallel_write_safe": True,
+    }
+
+
+log = getLogger("config_obj")
--- /dev/null
+++ b/slidge_sphinx_extensions/doap.py
@@ -0,0 +1,141 @@
+"""
+Sphinx extension to generate a table from a DOAP file in XML format.
+
+This is a helper to generate "features" pages for the docs of slidge-powered
+gateways.
+"""
+
+import xml.etree.ElementTree as ET
+from pathlib import Path
+
+import requests
+from docutils import nodes
+from sphinx.util.docutils import SphinxDirective
+from sphinx.util.logging import getLogger
+
+
+def parse(el):
+    status = el.find("{https://linkmauve.fr/ns/xmpp-doap#}status").text
+    url = el.find("{https://linkmauve.fr/ns/xmpp-doap#}xep").get(
+        "{http://www.w3.org/1999/02/22-rdf-syntax-ns#}resource"
+    )
+
+    note_elem = el.find("{https://linkmauve.fr/ns/xmpp-doap#}note")
+
+    if note_elem is not None:
+        note = note_elem.text
+    else:
+        note = ""
+
+    if not note:
+        note = DEFAULT_NOTE.get(status, status)
+
+    return url, status, note
+
+
+def get_xep_titles(xep_urls: list[str]):
+    xep_titles = {
+        "https://xmpp.org/extensions/xep-0045.html": "Multi-User Chat",
+        "https://xmpp.org/extensions/xep-0085.html": "Chat State Notifications",
+        "https://xmpp.org/extensions/xep-0184.html": "Message Delivery Receipts",
+        "https://xmpp.org/extensions/xep-0201.html": "Best Practices for Message Threads",
+        "https://xmpp.org/extensions/xep-0245.html": "The /me Command",
+        "https://xmpp.org/extensions/xep-0308.html": "Last Message Correction",
+        "https://xmpp.org/extensions/xep-0319.html": "Last User Interaction in Presence",
+        "https://xmpp.org/extensions/xep-0333.html": "Chat Markers",
+        "https://xmpp.org/extensions/xep-0363.html": "HTTP File Upload",
+        "https://xmpp.org/extensions/xep-0393.html": "Message Styling",
+        "https://xmpp.org/extensions/xep-0424.html": "Message Retraction",
+        "https://xmpp.org/extensions/xep-0444.html": "Message Reactions",
+        "https://xmpp.org/extensions/xep-0461.html": "Message Replies",
+    }
+    titles = []
+    for xep_url in xep_urls:
+        if xep_url in xep_titles:
+            titles.append(xep_titles[xep_url])
+        else:
+            titles.append("Unknown XEP")
+    return titles
+
+
+class Doap(SphinxDirective):
+    has_content = True
+
+    def run(self):
+        xml = ET.parse(Path(self.get_location()).parent / self.content[0])
+
+        table = nodes.table()
+        tgroup = nodes.tgroup()
+
+        colspec = nodes.colspec()
+
+        tgroup += colspec
+        tgroup += colspec
+        tgroup += colspec
+
+        table += tgroup
+
+        tbody = nodes.tbody()
+
+        xep_urls = []
+        statuses = []
+        notes = []
+
+        for el in xml.iter("{https://linkmauve.fr/ns/xmpp-doap#}SupportedXep"):
+            try:
+                url, status, note = parse(el)
+            except Exception as e:
+                log.error("Problem parsing %s", el, exc_info=e)
+                continue
+            xep_urls.append(url)
+            statuses.append(status)
+            notes.append(note)
+
+        xep_titles = get_xep_titles(xep_urls)
+        for url, status, note, title in zip(xep_urls, statuses, notes, xep_titles):
+            row = nodes.row()
+
+            entry = nodes.entry()
+            entry.append(nodes.Text(SUPPORT[status]))
+            row += entry
+
+            entry = nodes.entry()
+            outer = nodes.paragraph("")
+            ref = nodes.reference()
+            ref["refuri"] = url
+            ref.append(nodes.Text(title))
+            outer.append(ref)
+
+            entry.append(outer)
+            row += entry
+
+            entry = nodes.entry()
+            entry.append(nodes.Text(note))
+            row += entry
+
+            tbody += row
+
+        tgroup += tbody
+
+        return [table]
+
+
+def setup(app):
+    app.add_directive("doap", Doap)
+
+    return {
+        "version": "0.1",
+        "parallel_read_safe": True,
+        "parallel_write_safe": True,
+    }
+
+
+SUPPORT = {"complete": "✅", "wontfix": "❌", "planned": "🔮", "partial": "🤏"}
+DEFAULT_NOTE = {
+    "complete": "Supported",
+    "wontfix": "Unsupported",
+    "planned": "Planned",
+    "partial": "Partially supported",
+}
+
+log = getLogger("doap")
--- /dev/null
+++ b/slidge_sphinx_extensions/__init__.py
@@ -0,0 +1 @@
+#
