1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
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)
|