commit 198ece70a0b1fa06a78fd6c968852d1ce91aade7
parent 67c4e43941054267f6e9513448481cd4de0519f6
Author: lash <dev@holbrook.no>
Date: Tue, 15 Nov 2022 16:36:58 +0000
Comment output when using show tool
Diffstat:
8 files changed, 72 insertions(+), 13 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
@@ -1,6 +1,8 @@
- 0.2.0
* GPG signing of issue messages.
* Use visitor pattern for messages verifier
+ * View message log in show command
+ ? Option to dump comment attachment files when viewing with show
- 0.1.3
* Add command for adding MIME Multipart comments
- 0.1.2
diff --git a/piknik/basket.py b/piknik/basket.py
@@ -148,8 +148,8 @@ class Basket:
v = self.__msg.get(issue_id)
m = IssueMessage.parse(o, v.decode('utf-8'), envelope_callback=envelope_callback, message_callback=message_callback)
return m
- except FileNotFoundError:
- logg.debug('instantiating new message log for {}'.format(issue_id))
+ except FileNotFoundError as e:
+ logg.debug('instantiating new message log for {} {}'.format(issue_id, e))
return IssueMessage(o)
diff --git a/piknik/crypto.py b/piknik/crypto.py
@@ -49,20 +49,20 @@ class PGPSigner:
if env_header != 'pgp':
raise VerifyError('expected envelope type "pgp", but got {}'.format(env_header))
if self.__envelope_state > -1 and self.__envelope_state < 2:
- raise VerifyError('new envelope before previous was verified')
+ raise VerifyError('new envelope before previous was verified ({})'.format(self.__envelope_state))
self.__envelope = msg
self.__envelope_state = 0
def message_callback(self, envelope, msg, message_id):
- if msg.get('Content-Type') != 'application/pgp-signature':
- return
-
if self.__envelope_state == 0:
self.__envelope_state = 1
self.__envelope = msg
return
+ if msg.get('Content-Type') != 'application/pgp-signature':
+ return
+
v = self.__envelope.as_string()
sig = msg.get_payload()
(fd, fp) = tempfile.mkstemp()
diff --git a/piknik/msg.py b/piknik/msg.py
@@ -91,7 +91,8 @@ class IssueMessage:
r = f.read()
f.close()
r = b64encode(r)
- m.set_payload(str(r))
+ m.add_header('Content-Length', str(len(r)))
+ m.set_payload(r.decode())
return m
diff --git a/piknik/runnable/comment.py b/piknik/runnable/comment.py
@@ -9,10 +9,11 @@ from piknik import Issue
from piknik.store import FileStoreFactory
from piknik.crypto import PGPSigner
+logging.basicConfig(level=logging.DEBUG)
+
next_i = 1
def next_message_arg():
global next_i
- print('next {}'.format(next_i))
r = sys.argv[next_i]
@@ -39,7 +40,7 @@ arg = argp.parse_args(sys.argv[1:])
signer = PGPSigner(default_key=arg.s, use_agent=True)
store_factory = FileStoreFactory(arg.d)
-basket = Basket(store_factory, message_wrapper=signer.sign, message_verifier=signer.verify)
+basket = Basket(store_factory, message_wrapper=signer.sign)
def main():
diff --git a/piknik/runnable/show.py b/piknik/runnable/show.py
@@ -1,9 +1,18 @@
+# standard imports
import sys
import argparse
+import logging
+from base64 import b64decode
+from email.utils import parsedate_to_datetime
+# external imports
+from mimeparse import parse_mime_type
+
+# local imports
from piknik import Basket
from piknik import Issue
from piknik.store import FileStoreFactory
+from piknik.crypto import PGPSigner
argp = argparse.ArgumentParser()
@@ -16,6 +25,52 @@ store_factory = FileStoreFactory(arg.d)
basket = Basket(store_factory)
+# TODO can implement as email parser api instead?
+class PGPWrapper(PGPSigner):
+
+ def __init__(self, home_dir=None):
+ super(PGPWrapper, self).__init__(home_dir=home_dir)
+ self.message_date = None
+
+
+ def render_message(self, message, message_id):
+ r = None
+ m = parse_mime_type(message.get_content_type())
+ print('content {}'.format(m))
+
+ if m[0] == 'text':
+ if m[1] == 'plain':
+ r = message.get_payload()
+ if message.get('Content-Transfer-Encoding') == 'BASE64':
+ r = b64decode(r).decode()
+ else:
+ r = '[rich text]'
+ else:
+ sz = message.get('Content-Length')
+ if sz == None:
+ sz = 'unknown'
+ r = '[file: ' + message.get_filename() + ', size: ' + sz + ']'
+
+ print("message {} - {}\n\t{}\n".format(self.message_date, message_id, r))
+
+
+ def message_callback(self, envelope, message, message_id):
+ super(PGPWrapper, self).message_callback(envelope, message, message_id)
+
+ if message_id == None:
+ return
+
+ if message.get('X-Piknik-Msg-Id') == None:
+ if message.get('Content-Type') == 'application/pgp-signature':
+ return
+ self.render_message(message, message_id)
+ else:
+ d = message.get('Date')
+ self.message_date = parsedate_to_datetime(d)
+
+verifier = PGPWrapper()
+
+
def render_default(b, o, t):
print("""id: {}
title: {}
@@ -42,9 +97,7 @@ tags: {}
s += ' (owner)'
print('\t' + str(s))
- m = basket.get_msg(arg.issue_id)
- print()
- print(m)
+ m = basket.get_msg(arg.issue_id, envelope_callback=verifier.envelope_callback, message_callback=verifier.message_callback)
def main():
diff --git a/piknik/store/__init__.py b/piknik/store/__init__.py
@@ -34,11 +34,12 @@ class MsgDir(HexDir):
def key_to_string(self, k):
u = uuid.UUID(bytes=k)
- return str(u)
+ return u.bytes.hex()
def put(self, k, v):
u = uuid.UUID(k)
+ print('putting {}'.format(u.bytes.hex()))
return self.add(u.bytes, v)
diff --git a/requirements.txt b/requirements.txt
@@ -1,3 +1,4 @@
shep~=0.3.0
leveldir~=0.3.1
python-gnupg~=0.5.0
+python-mimeparse~=1.6.0