From 030fa1d90e8331035dbfcb39b75d573976b495fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Thu, 1 Dec 2022 05:24:26 +0100 Subject: Move maildir stuff to own directory. --- mu4web/maildir.py | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 mu4web/maildir.py (limited to 'mu4web/maildir.py') diff --git a/mu4web/maildir.py b/mu4web/maildir.py new file mode 100644 index 0000000..831f23d --- /dev/null +++ b/mu4web/maildir.py @@ -0,0 +1,88 @@ +from dataclasses import dataclass +import os.path + +from html_render import HTML +from util import find + +from urllib.parse import urlencode + +from typing import ( + Union +) + +try: + from natsort import natsorted +except ModuleNotFoundError: + natsorted = sorted + +@dataclass +class MaildirEntry: + """A single maildir, used by find_maildirs.""" + name: str + + +@dataclass +class MaildirGroup: + """A group of maildir, which isn't a maildir in itself.""" + name: str + children: list[Union[MaildirEntry, 'MaildirGroup']] + + +def _build_tree(items: list[list[str]]) -> MaildirGroup: + groups: dict[str, list[list[str]]] = {} + direct: list[MaildirEntry] = [] + for key, *rest in items: + if rest: + groups.setdefault(key, []).append(rest) + else: + direct.append(MaildirEntry(key)) + + node = MaildirGroup('root', []) + for key, values in groups.items(): + next = _build_tree(values) + next.name = key + node.children.append(next) + node.children.extend(direct) + return node + + + +def find_maildirs(basedir) -> MaildirGroup: + """ + Find all maildirs located under basedir. + + A maildir is defined as any directory which contains a `cur` + directory. + + Returns a MaildirGroup of the root, whose children will be all the + maildirs under basedir. Note that if a directory is both a maildir + and a group of maildirs then it will have two separate entries. + """ + basedir = basedir.rstrip('/') + files = find(basedir, type='d', name='cur') + # + 1 removes leading slash + # - 4 removes '/cur' + dirs = [entry[len(basedir)+1:-4].decode('UTF-8').split(os.path.sep) + for entry in files] + + return _build_tree(dirs) + + +def serialize_maildir(maildir: MaildirGroup, path: list[str] = []) -> HTML: + """Build a (recursive) list from a maildir node.""" + entries: list[HTML] = [] + for node in natsorted(maildir.children, key=lambda n: n.name): + if isinstance(node, MaildirEntry): + parts = '/'.join(path + [node.name]) + url = 'search?' + urlencode({'q': f'maildir:"/{parts}"'}) + entry = ('li', ('a', {'href': url}, + node.name or ('i', 'root'))) + else: + entry = ('li', + ('details', + ('summary', node.name), + serialize_maildir(node, path + [node.name]))) + entries.append(entry) + + return ('ul', *entries) + -- cgit v1.2.3