aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHugo Hörnquist <hugo@lysator.liu.se>2022-10-31 08:10:04 +0100
committerHugo Hörnquist <hugo@lysator.liu.se>2022-10-31 08:51:15 +0100
commite89ec3a1e1a94bab33ca6f4bcdd2147de52f2c2c (patch)
tree7317334ec370fed7b435e3ea452757784c494c06
parentIntroduce types. (diff)
downloadmu4web-e89ec3a1e1a94bab33ca6f4bcdd2147de52f2c2c.tar.gz
mu4web-e89ec3a1e1a94bab33ca6f4bcdd2147de52f2c2c.tar.xz
Move stuff to sub-files.
-rw-r--r--html_render.py45
-rw-r--r--main.py110
-rw-r--r--mu.py66
3 files changed, 114 insertions, 107 deletions
diff --git a/html_render.py b/html_render.py
new file mode 100644
index 0000000..533ae7c
--- /dev/null
+++ b/html_render.py
@@ -0,0 +1,45 @@
+import html
+from typing import (
+ TypeAlias,
+ Union,
+ Callable,
+ Optional,
+ cast,
+)
+
+HTML: TypeAlias = Union[tuple, list, Callable[[], str], None,
+ str, int, float]
+
+
+standalones = ['hr', 'br', 'meta']
+
+
+def _render_document(document: HTML) -> str:
+ if type(document) == tuple:
+ tag, *body = document
+ if body and type(body[0]) == dict:
+ print(body[0])
+ attributes = ' '.join(f'{a}="{html.escape(b)}"'
+ for a, b in body[0].items())
+ body = body[1:]
+ start = f'<{tag} {attributes}>'
+ else:
+ start = f'<{tag}>'
+ if tag in standalones:
+ return start
+ else:
+ items = ''.join(_render_document(b) for b in body)
+ return start + f'{items}</{tag}>'
+ elif callable(document):
+ return str(document())
+ elif type(document) == list:
+ return ''.join(_render_document(e) for e in document)
+ elif document is None:
+ return ''
+ else:
+ # strings, and everything else
+ return html.escape(str(document))
+
+
+def render_document(document: HTML) -> str:
+ return '<!doctype html>\n' + _render_document(document)
diff --git a/main.py b/main.py
index 1ee89de..a8b5205 100644
--- a/main.py
+++ b/main.py
@@ -1,47 +1,21 @@
-import subprocess
-import email
-import email.message
from email.message import EmailMessage
from email.headerregistry import Address
-from subprocess import PIPE
-import html
-from email.parser import BytesParser
-import email.policy
from urllib.parse import urlparse, urlencode, parse_qs
from http.cookies import BaseCookie
import http.cookies
import password
from password import Passwords
from uuid import uuid4
-import xml.dom.minidom
-import xml.dom
import os
from typing import (
- TypeAlias,
- Union,
- Callable,
Optional,
cast,
)
+from mu import mu_search, get_mail
+from html_render import HTML, render_document
from http.server import HTTPServer, BaseHTTPRequestHandler
-HTML: TypeAlias = Union[tuple, list, Callable[[], str], None,
- str, int, float]
-
-parser = BytesParser(policy=email.policy.default)
-
-
-def get_mail(id: str) -> email.message.Message:
- cmd = subprocess.run(['mu', 'find', '-u', f'i:{id}',
- '--fields', 'l'],
- stdout=PIPE)
- filename = cmd.stdout.decode('UTF-8').strip()
-
- with open(filename, "rb") as f:
- mail = parser.parse(f)
- return mail
-
def mailto(addr: str) -> HTML:
return ('a', {'href': f'mailto:{addr}'}, addr)
@@ -66,40 +40,6 @@ def header_format(key: str, value) -> HTML:
return value
-standalones = ['hr', 'br', 'meta']
-
-
-def _render_document(document: HTML) -> str:
- if type(document) == tuple:
- tag, *body = document
- if body and type(body[0]) == dict:
- print(body[0])
- attributes = ' '.join(f'{a}="{html.escape(b)}"'
- for a, b in body[0].items())
- body = body[1:]
- start = f'<{tag} {attributes}>'
- else:
- start = f'<{tag}>'
- if tag in standalones:
- return start
- else:
- items = ''.join(_render_document(b) for b in body)
- return start + f'{items}</{tag}>'
- elif callable(document):
- return str(document())
- elif type(document) == list:
- return ''.join(_render_document(e) for e in document)
- elif document is None:
- return ''
- else:
- # strings, and everything else
- return html.escape(str(document))
-
-
-def render_document(document: HTML) -> str:
- return '<!doctype html>\n' + _render_document(document)
-
-
style: HTML = lambda: """
nav {
display: block;
@@ -242,51 +182,6 @@ def search_field(q: str) -> HTML:
('input', {'type': 'Submit'}))
-class MuError(Exception):
- codes = {
- 1: 'General Error',
- 2: 'No Matches',
- 4: 'Database is corrupted'
- }
-
- def __init__(self, returncode: int):
- self.returncode: int = returncode
- self.msg: str = MuError.codes.get(returncode, 'Unknown Error')
-
- def __repr__(self):
- return f'MuError({self.returncode}, "{self.msg}")'
-
-
-def mu_search(query, sortfield='subject', reverse=False):
- if not query:
- raise ValueError('Query required for mu_search')
- cmdline = ['mu', 'find',
- '--format=xml',
- query,
- '--sortfield', sortfield]
- if reverse:
- cmdline.append('--reverse')
- cmd = subprocess.Popen(cmdline, stdout=subprocess.PIPE)
- dom = xml.dom.minidom.parse(cmd.stdout)
- if returncode := cmd.wait():
- raise MuError(returncode)
-
- message_list = []
- messages = dom.childNodes[0]
- assert messages.localName == 'messages'
- for message in messages.childNodes:
- msg_dict = {}
- if message.nodeType != xml.dom.Node.ELEMENT_NODE:
- continue
- for kv in message.childNodes:
- if kv.nodeType != xml.dom.Node.ELEMENT_NODE:
- continue
- msg_dict[kv.localName] = kv.childNodes[0].data
- message_list.append(msg_dict)
-
- return message_list
-
-
def search_result(q, by, reverse):
keys = ['From', 'To', 'Subject', 'Date', 'Size', 'Maildir', 'Msgid']
@@ -457,6 +352,7 @@ class Handler(BaseHTTPRequestHandler):
self.send_header('location', '/')
else:
self.send_response(302)
+ self.send_header('location', '/')
self.end_headers()
diff --git a/mu.py b/mu.py
new file mode 100644
index 0000000..93816f4
--- /dev/null
+++ b/mu.py
@@ -0,0 +1,66 @@
+import email.message
+import email.policy
+from email.parser import BytesParser
+import subprocess
+from subprocess import PIPE
+import xml.dom.minidom
+import xml.dom
+
+
+parser = BytesParser(policy=email.policy.default)
+
+
+def get_mail(id: str) -> email.message.Message:
+ cmd = subprocess.run(['mu', 'find', '-u', f'i:{id}',
+ '--fields', 'l'],
+ stdout=PIPE)
+ filename = cmd.stdout.decode('UTF-8').strip()
+
+ with open(filename, "rb") as f:
+ mail = parser.parse(f)
+ return mail
+
+
+class MuError(Exception):
+ codes = {
+ 1: 'General Error',
+ 2: 'No Matches',
+ 4: 'Database is corrupted'
+ }
+
+ def __init__(self, returncode: int):
+ self.returncode: int = returncode
+ self.msg: str = MuError.codes.get(returncode, 'Unknown Error')
+
+ def __repr__(self):
+ return f'MuError({self.returncode}, "{self.msg}")'
+
+
+def mu_search(query, sortfield='subject', reverse=False):
+ if not query:
+ raise ValueError('Query required for mu_search')
+ cmdline = ['mu', 'find',
+ '--format=xml',
+ query,
+ '--sortfield', sortfield]
+ if reverse:
+ cmdline.append('--reverse')
+ cmd = subprocess.Popen(cmdline, stdout=subprocess.PIPE)
+ dom = xml.dom.minidom.parse(cmd.stdout)
+ if returncode := cmd.wait():
+ raise MuError(returncode)
+
+ message_list = []
+ messages = dom.childNodes[0]
+ assert messages.localName == 'messages'
+ for message in messages.childNodes:
+ msg_dict = {}
+ if message.nodeType != xml.dom.Node.ELEMENT_NODE:
+ continue
+ for kv in message.childNodes:
+ if kv.nodeType != xml.dom.Node.ELEMENT_NODE:
+ continue
+ msg_dict[kv.localName] = kv.childNodes[0].data
+ message_list.append(msg_dict)
+
+ return message_list