aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHugo Hörnquist <hugo@lysator.liu.se>2022-12-01 05:24:26 +0100
committerHugo Hörnquist <hugo@lysator.liu.se>2022-12-01 05:29:33 +0100
commit030fa1d90e8331035dbfcb39b75d573976b495fa (patch)
treeb9019c5719e8f233ae735303cd8839c7eba2308a
parentFix scanning of maildirs. (diff)
downloadmu4web-030fa1d90e8331035dbfcb39b75d573976b495fa.tar.gz
mu4web-030fa1d90e8331035dbfcb39b75d573976b495fa.tar.xz
Move maildir stuff to own directory.
-rw-r--r--mu4web/maildir.py88
-rw-r--r--mu4web/main.py80
-rw-r--r--mu4web/util.py10
3 files changed, 99 insertions, 79 deletions
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)
+
diff --git a/mu4web/main.py b/mu4web/main.py
index 4d39c1a..d57cc64 100644
--- a/mu4web/main.py
+++ b/mu4web/main.py
@@ -23,9 +23,8 @@ import mu
from html_render import HTML, render_document
from user.local import LocalUser
from user.pam import PamUser
+from maildir import find_maildirs, serialize_maildir
-import subprocess
-from dataclasses import dataclass
import flask
from flask import (
@@ -38,10 +37,6 @@ from flask import (
get_flashed_messages
)
-try:
- from natsort import natsorted
-except ModuleNotFoundError:
- natsorted = sorted
#
# A few operations depend on the index of attachements. These index
@@ -333,79 +328,6 @@ def search_page(q: str, by: Optional[mu.Sortfield],
body=main_body))
-@dataclass
-class Leaf:
- name: str
-
-@dataclass
-class Node:
- name: str
- children: list[Union[Leaf, 'Node']]
-
-
-def build_tree(items: list[list[str]]) -> Node:
- groups: dict[str, list[list[str]]] = {}
- direct: list[Leaf] = []
- for key, *rest in items:
- if rest:
- groups.setdefault(key, []).append(rest)
- else:
- direct.append(Leaf(key))
-
- node = Node('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(basedir, **flags) -> list[bytes]:
- cmdline = ['find', basedir]
- for key, value in flags.items():
- cmdline += [f'-{key}', value]
- cmdline.append('-print0')
-
- cmd = subprocess.run(cmdline, capture_output=True)
- return cmd.stdout.split(b'\0')[:-1]
-
-
-def find_maildirs(basedir) -> Node:
- """
- Find all maildirs located under basedir.
-
- A maildir is defined as any directory which contains a `cur`
- directory.
- """
- 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: Node, 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, Leaf):
- 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)
-
def index_page():
data = mu.info()
maildirs = find_maildirs(data['maildir'] + '/')
diff --git a/mu4web/util.py b/mu4web/util.py
new file mode 100644
index 0000000..c742cd6
--- /dev/null
+++ b/mu4web/util.py
@@ -0,0 +1,10 @@
+import subprocess
+
+def find(basedir, **flags) -> list[bytes]:
+ cmdline = ['find', basedir]
+ for key, value in flags.items():
+ cmdline += [f'-{key}', value]
+ cmdline.append('-print0')
+
+ cmd = subprocess.run(cmdline, capture_output=True)
+ return cmd.stdout.split(b'\0')[:-1]