commit c2d48d48b1f09239dd3a2b603c5c1f44ef589d89 Author: Valentin Ochs Date: Fri May 10 22:52:08 2019 +0200 Initial commit diff --git a/mailcap-client.py b/mailcap-client.py new file mode 100644 index 0000000..e4d6fbd --- /dev/null +++ b/mailcap-client.py @@ -0,0 +1,18 @@ +#!python3 +import struct +import socket +import os +import sys +import mimetypes + +s = socket.socket(socket.AF_UNIX) +s.connect(os.path.join(os.environ["HOME"], ".mailcap.sock")) + +file = sys.argv[1] +mime = mimetypes.guess_type(file)[0] +data = open(file, "rb").read() + +def strtr(x, c="B"): + return struct.pack(c, len(x)) + x + +s.sendall(strtr(file.encode('utf-8')) + strtr(mime.encode('utf-8')) + strtr(data, "!I")) diff --git a/mailcap-server.py b/mailcap-server.py new file mode 100644 index 0000000..1e6c5e4 --- /dev/null +++ b/mailcap-server.py @@ -0,0 +1,119 @@ +#!python3 +import struct +import socket +import os +import tempfile +import mailcap +import sys + +sockpath = "mailcap.sock" + +if os.path.exists(sockpath): + os.remove(sockpath) + +class Server(object): + class Connection(object): + def __init__(self, conn): + self._conn = conn + + def timeout(self, timeout): + return self._conn.settimeout(timeout) + + def close(self): + self._conn.close() + + def recv(self, size): + data = self._conn.recv(size) + return data + + def recv_exact(self, length): + retval = bytes() + while len(retval) < length: + data = self.recv(length - len(retval)) + if len(data) == 0: + return None + retval += data + return retval + + def __init__(self, path="mailcap.sock"): + self._socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + self._socket.bind(path) + self._socket.listen(3) + self._dir = tempfile.TemporaryDirectory() + + def close(self): + self._socket.close() + self._dir.cleanup() + + def next_file(self, initial_timeout=None, timeout=5): + conn = self.Connection(self._socket.accept()[0]) + conn.timeout(initial_timeout) + + data = conn.recv_exact(1) + if data is None: + return None + fn_len = struct.unpack("B", data)[0] + + conn.timeout(timeout) + + data = conn.recv_exact(fn_len) + if data is None: + return None + fn = data.decode('utf-8') + fn = fn.replace("/", "_") + if len(fn) == 0 or fn in ['.', '..']: + return None + + data = conn.recv_exact(1) + if data is None: + return None + mime_len = struct.unpack("B", data)[0] + + data = conn.recv_exact(mime_len) + if data is None: + return None + mime = data.decode('utf-8') + + data = conn.recv_exact(4) + if data is None: + return None + file_len = struct.unpack("!I", data)[0] + + print(fn, mime) + + fn = os.path.join(self._dir.name, fn) + with open(fn, "wb+") as f: + while file_len > 0: + data = conn.recv(min(4096, file_len)) + f.write(data) + file_len -= len(data) + + conn.close() + + if file_len is 0: + return fn, mime + else: + os.remove(fn) + return None + +if __name__ == "__main__": + if len(sys.argv) > 1: + if sys.argv[1] == "-h": + print("Usage: %s [socket_path = mailcap.sock]" % (sys.argv[0],)) + exit() + else: + sockpath = sys.argv[1] + if os.path.exists(sockpath): + os.remove(sockpath) + sv = Server(sockpath) + caps = mailcap.getcaps() + while True: + rv = sv.next_file() + if rv: + f, mime = rv + print(f, mime) + match = mailcap.findmatch(caps, mime, filename=f) + if match: + os.system(match[0]) + if 'nodelete' not in match[1]: + os.remove(f)