summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJannis M. Hoffmann <jannis@fehcom.de>2024-12-12 16:41:13 +0100
committerJannis M. Hoffmann <jannis@fehcom.de>2024-12-12 16:41:13 +0100
commit0237cc4bac0dafa9a3f3013b3f48e4f2941963bd (patch)
tree48b2fa89842b73de41bac93e24a0e3aef2bb866c
parent55688b969a645fbc6d94c76f51da3be976c1d098 (diff)
fixes and improvements for error handling
-rw-r--r--src/jwebmail/__init__.py2
-rw-r--r--src/jwebmail/model/read_mails.py61
-rw-r--r--src/jwebmail/read_mails.py2
-rw-r--r--src/jwebmail/webmail.py9
4 files changed, 58 insertions, 16 deletions
diff --git a/src/jwebmail/__init__.py b/src/jwebmail/__init__.py
index b4c01a1..904c3b8 100644
--- a/src/jwebmail/__init__.py
+++ b/src/jwebmail/__init__.py
@@ -36,7 +36,7 @@ else:
toml_read_file = dict(load=toml_load, text=True)
-__version__ = "2.8.2.dev1"
+__version__ = "2.8.3.dev0"
csrf = CSRFProtect()
diff --git a/src/jwebmail/model/read_mails.py b/src/jwebmail/model/read_mails.py
index 534f2f7..c9cee7a 100644
--- a/src/jwebmail/model/read_mails.py
+++ b/src/jwebmail/model/read_mails.py
@@ -1,5 +1,6 @@
import os
from base64 import b64decode
+from functools import wraps
from socket import socketpair
import varlink
@@ -11,6 +12,28 @@ class QMAuthError(Exception):
self.rc = rc
+class JWebmailMailStorageError(Exception):
+ def __init__(self, err, params):
+ self.name = err
+ self.parameters = params
+
+
+def remap_errors(func):
+ prefix = "de.jmhoffmann.jwebmail.mail-storage."
+
+ @wraps(func)
+ def decorator(*args, **kvargs):
+ try:
+ return func(*args, **kvargs)
+ except varlink.VarlinkError as ex:
+ if (name := ex.error().removeprefix(prefix)) != ex.error():
+ raise JWebmailMailStorageError(name, ex.parameters())
+ else:
+ raise
+
+ return decorator
+
+
class QMailAuthuser:
def __init__(self, prog, mailbox_path, virtual_user, authenticator):
self._prog = prog
@@ -23,6 +46,7 @@ class QMailAuthuser:
self._client = None
self._connection = None
+ @remap_errors
def list_search(self, folder, bound, after, limit, sort, search):
sort_val = dict()
if sort[0] == "!":
@@ -64,6 +88,7 @@ class QMailAuthuser:
req["last"],
)
+ @remap_errors
def count(self, folder):
resp = self._connection.Stats(folder=folder)
return {
@@ -72,6 +97,7 @@ class QMailAuthuser:
"unread_mails": resp["unread_count"],
}
+ @remap_errors
def show(self, folder, msgid):
resp = self._connection.Show(folder=folder, mid=msgid)
return {
@@ -79,6 +105,7 @@ class QMailAuthuser:
"body": self._mail_body(resp["mail"]["body"]),
}
+ @remap_errors
def raw(self, folder, mid, path):
resp = self._connection.Raw(folder=folder, mid=mid, path=path)
return {
@@ -86,18 +113,22 @@ class QMailAuthuser:
"body": b64decode(resp["body"]),
}
+ @remap_errors
def folders(self):
resp = self._connection.Folders()
return list(resp["folders"]) + [""]
+ @remap_errors
def move(self, mid, from_f, to_f):
self._connection.Move(mid=mid, from_folder=from_f, to_folder=to_f)
return True
+ @remap_errors
def remove(self, folder, msgid):
self._connection.Remove(folder=folder, mid=msgid)
return True
+ @remap_errors
def add_folder(self, name):
resp = self._connection.AddFolder(name=name)
return resp["status"]
@@ -176,8 +207,8 @@ class QMailAuthuser:
assert False
def open(self, username, password):
- (rp, wp) = os.pipe()
- (sp, sc) = socketpair()
+ rp, wp = os.pipe()
+ sp, sc = socketpair()
cmdline = [self._authenticator, self._prog]
if (pid := os.fork()) == 0:
# child
@@ -204,24 +235,32 @@ class QMailAuthuser:
"de.jmhoffmann.jwebmail.mail-storage", connection=sp
)
except ConnectionResetError:
- (pid, status) = os.waitpid(pid, os.WNOHANG)
- if pid != 0:
- raise QMAuthError(os.waitstatus_to_exitcode(status))
+ pid, status = os.waitpid(self._pid, 0)
+ if (rc := os.waitstatus_to_exitcode(status)) != 0:
+ raise QMAuthError(rc)
else:
raise
user = username[: username.index("@")]
- self._connection.Init(
- unix_user=self._virtual_user,
- mailbox_path=os.path.join(self._mailbox_path, user),
- )
+ try:
+ self._connection.Init(
+ unix_user=self._virtual_user,
+ mailbox_path=os.path.join(self._mailbox_path, user),
+ )
+ except BrokenPipeError:
+ pid, status = os.waitpid(self._pid, 0)
+ assert pid == self._pid
+ if (rc := os.waitstatus_to_exitcode(status)) != 0:
+ raise QMAuthError(rc)
+ else:
+ raise
return self
def close(self):
self._connection.close()
self._socket.close()
- (pid, status) = os.waitpid(self._pid, 0)
+ pid, status = os.waitpid(self._pid, 0)
assert pid == self._pid
rc = os.waitstatus_to_exitcode(status)
if rc != 0:
@@ -234,7 +273,7 @@ class QMailAuthuser:
if ex_val is None:
self.close()
elif issubclass(ex_type, BrokenPipeError):
- (pid, _status) = os.waitpid(self._pid, 0)
+ pid, _status = os.waitpid(self._pid, 0)
assert pid == self._pid
return False
diff --git a/src/jwebmail/read_mails.py b/src/jwebmail/read_mails.py
index 8e1a23d..f88ce46 100644
--- a/src/jwebmail/read_mails.py
+++ b/src/jwebmail/read_mails.py
@@ -173,8 +173,8 @@ def _build_qma(domain):
def login(username, password):
+ _, domain = username.split("@")
try:
- _, domain = username.split("@")
_build_qma(domain).open(username, password)
except QMAuthError as err:
if err.rc == 1:
diff --git a/src/jwebmail/webmail.py b/src/jwebmail/webmail.py
index d260e8a..6c0b6c2 100644
--- a/src/jwebmail/webmail.py
+++ b/src/jwebmail/webmail.py
@@ -26,7 +26,7 @@ from wtforms import (
validators,
)
-from .model.read_mails import QMAuthError
+from .model.read_mails import JWebmailMailStorageError
from .read_mails import get_read_mails_logged_in
from .read_mails import login as rm_login
from .render_mail import to_mime_type
@@ -165,8 +165,11 @@ def readmail(msgid, folder=""):
if format == "html":
try:
mail = read_mails.show(folder, msgid)
- except QMAuthError:
- return render_template("not_found.html"), 404
+ except JWebmailMailStorageError as ex:
+ if ex.name == "InvalidMID":
+ return render_template("not_found.html"), 404
+ else:
+ raise
return render_template("readmail.html", msg=mail, folder=folder)