class ReplyInfo (object):
def __init__(self):
self.replies = None
+
+ self.target_key = None
+ self.fallback_target_key = None
self.msg_to_quote = ""
self.success_decrypt = False
replyinfo_obj.replies = lang.replies
prepare_for_reply(email_struct, replyinfo_obj)
+ encrypt_to_key = get_key_from_fp(replyinfo_obj, gpgme_ctx)
reply_plaintext = write_reply(replyinfo_obj)
- print(reply_plaintext)
+ # TODO error handling for missing keys and setting .no_public_key
+ reply_mime = generate_encrypted_mime(reply_plaintext, email_from, \
+ email_subject, encrypt_to_key,
+ gpgme_ctx)
-# encrypt_to_key = choose_reply_encryption_key(gpgme_ctx, fingerprints)
-#
-# reply_mime = generate_encrypted_mime(plaintext, email_from, \
-# email_subject, encrypt_to_key,
-# gpgme_ctx)
+ print(reply_mime)
def get_gpg_context (gnupghome, sign_with_key_fp):
email_struct = email.parser.Parser().parsestr(email_text)
- eddy_obj = parse_mime(email_struct)
- split_payloads(eddy_obj)
- gpg_on_payloads(eddy_obj, gpgme_ctx)
+ eddymsg_obj = parse_mime(email_struct)
+ split_payloads(eddymsg_obj)
+ gpg_on_payloads(eddymsg_obj, gpgme_ctx)
- return eddy_obj
+ return eddymsg_obj
def parse_mime(msg_struct):
- eddy_obj = EddyMsg()
+ eddymsg_obj = EddyMsg()
if msg_struct.is_multipart() == True:
payloads = msg_struct.get_payload()
- eddy_obj.multipart = True
- eddy_obj.subparts = list(map(parse_mime, payloads))
+ eddymsg_obj.multipart = True
+ eddymsg_obj.subparts = list(map(parse_mime, payloads))
else:
- eddy_obj = get_subpart_data(msg_struct)
+ eddymsg_obj = get_subpart_data(msg_struct)
- return eddy_obj
+ return eddymsg_obj
def scan_and_split (payload_piece, match_type, pattern):
return obj
-def do_to_eddys_pieces (function_to_do, eddy_obj, data):
+def do_to_eddys_pieces (function_to_do, eddymsg_obj, data):
- if eddy_obj.multipart == True:
- for sub in eddy_obj.subparts:
+ if eddymsg_obj.multipart == True:
+ for sub in eddymsg_obj.subparts:
do_to_eddys_pieces(function_to_do, sub, data)
else:
- function_to_do(eddy_obj, data)
+ function_to_do(eddymsg_obj, data)
-def split_payloads (eddy_obj):
+def split_payloads (eddymsg_obj):
for match_type in match_types:
- do_to_eddys_pieces(split_payload_pieces, eddy_obj, match_type)
+ do_to_eddys_pieces(split_payload_pieces, eddymsg_obj, match_type)
-def split_payload_pieces (eddy_obj, match_type):
+def split_payload_pieces (eddymsg_obj, match_type):
(match_name, pattern) = match_type
new_pieces_list = []
- for piece in eddy_obj.payload_pieces:
+ for piece in eddymsg_obj.payload_pieces:
new_pieces_list += scan_and_split(piece, match_name, pattern)
- eddy_obj.payload_pieces = new_pieces_list
+ eddymsg_obj.payload_pieces = new_pieces_list
-def gpg_on_payloads (eddy_obj, gpgme_ctx, prev_parts=[]):
+def gpg_on_payloads (eddymsg_obj, gpgme_ctx, prev_parts=[]):
- if eddy_obj.multipart == True:
+ if eddymsg_obj.multipart == True:
prev_parts=[]
- for sub in eddy_obj.subparts:
+ for sub in eddymsg_obj.subparts:
gpg_on_payloads (sub, gpgme_ctx, prev_parts)
prev_parts += [sub]
return
- for piece in eddy_obj.payload_pieces:
+ for piece in eddymsg_obj.payload_pieces:
if piece.piece_type == "text":
# don't transform the plaintext.
pass
elif piece.piece_type == "message":
- (plaintext, sigs) = decrypt_block (piece.string, gpgme_ctx)
+ (plaintext, sigs) = decrypt_block(piece.string, gpgme_ctx)
if plaintext:
piece.gpg_data = GPGData()
+ piece.gpg_data.decrypted = True
piece.gpg_data.sigs = sigs
# recurse!
piece.gpg_data.plainobj = parse_pgp_mime(plaintext, gpgme_ctx)
piece.gpg_data.sigs = sig_fps
piece.gpg_data.plainobj = prev
break
+
else:
pass
-def prepare_for_reply (eddy_obj, replyinfo_obj):
+def prepare_for_reply (eddymsg_obj, replyinfo_obj):
- do_to_eddys_pieces(prepare_for_reply_pieces, eddy_obj, replyinfo_obj)
+ do_to_eddys_pieces(prepare_for_reply_pieces, eddymsg_obj, replyinfo_obj)
+def prepare_for_reply_pieces (eddymsg_obj, replyinfo_obj):
-def prepare_for_reply_pieces (eddy_obj, replyinfo_obj):
-
- for piece in eddy_obj.payload_pieces:
+ for piece in eddymsg_obj.payload_pieces:
if piece.piece_type == "text":
# don't quote the plaintext part.
pass
replyinfo_obj.failed_decrypt = True
else:
replyinfo_obj.success_decrypt = True
- # TODO: only quote it if it is also signed by the encrypter.
- replyinfo_obj.msg_to_quote += flatten_payloads(piece.gpg_data.plainobj)
+ if replyinfo_obj.target_key != None:
+ continue
+ if piece.gpg_data.sigs != []:
+ replyinfo_obj.target_key = piece.gpg_data.sigs[0]
+ replyinfo_obj.msg_to_quote = flatten_payloads(piece.gpg_data.plainobj)
+
+ # to catch public keys in encrypted blocks
prepare_for_reply(piece.gpg_data.plainobj, replyinfo_obj)
elif piece.piece_type == "pubkey":
else:
replyinfo_obj.sig_success = True
+ if replyinfo_obj.fallback_target_key == None:
+ replyinfo_obj.fallback_target_key = piece.gpg_data.sigs[0]
-def flatten_payloads (eddy_obj):
+
+
+def flatten_payloads (eddymsg_obj):
flat_string = ""
- if eddy_obj.multipart == True:
- for sub in eddy_obj.subparts:
+ if eddymsg_obj == None:
+ return ""
+
+ if eddymsg_obj.multipart == True:
+ for sub in eddymsg_obj.subparts:
flat_string += flatten_payloads (sub)
return flat_string
- for piece in eddy_obj.payload_pieces:
+ # todo: don't include nested decrypted messages.
+ for piece in eddymsg_obj.payload_pieces:
if piece.piece_type == "text":
flat_string += piece.string
+ elif piece.piece_type == "message":
+ flat_string += flatten_payloads(piece.plainobj)
+ elif ((piece.piece_type == "clearsign") \
+ or (piece.piece_type == "detachedsig")) \
+ and (piece.gpg_data != None):
+ flat_string += flatten_payloads (piece.gpg_data.plainobj)
+
return flat_string
+def get_key_from_fp (replyinfo_obj, gpgme_ctx):
+
+ if replyinfo_obj.target_key == None:
+ replyinfo_obj.target_key = replyinfo_obj.fallback_target_key
+
+ if replyinfo_obj.target_key != None:
+ try:
+ encrypt_to_key = gpgme_ctx.get_key(replyinfo_obj.target_key)
+ return encrypt_to_key
+
+ except:
+ pass
+
+ # no available key to use
+ replyinfo_obj.target_key = None
+ replyinfo_obj.fallback_target_key = None
+
+ replyinfo_obj.no_public_key = True
+ replyinfo_obj.public_key_received = False
+
+ return None
+
+
def write_reply (replyinfo_obj):
reply_plain = ""
if replyinfo_obj.success_decrypt == True:
- quoted_text = email_quote_text(replyinfo_obj.msg_to_quote)
reply_plain += replyinfo_obj.replies['success_decrypt']
- reply_plain += quoted_text
+
+ if replyinfo_obj.no_public_key == False:
+ quoted_text = email_quote_text(replyinfo_obj.msg_to_quote)
+ reply_plain += quoted_text
elif replyinfo_obj.failed_decrypt == True:
reply_plain += replyinfo_obj.replies['failed_decrypt']
return ("",[])
plaintext = plain_b.getvalue().decode('utf-8')
- return (plaintext, sigs)
+
+ fingerprints = []
+ for sig in sigs:
+ fingerprints += [sig.fpr]
+ return (plaintext, fingerprints)
def choose_reply_encryption_key (gpgme_ctx, fingerprints):
def generate_encrypted_mime (plaintext, email_from, email_subject, encrypt_to_key,
gpgme_ctx):
+ # quoted printable encoding lets most ascii characters look normal
+ # before the decrypted mime message is decoded.
+ char_set = email.charset.Charset("utf-8")
+ char_set.body_encoding = email.charset.QP
- reply = "To: " + email_from + "\n"
- reply += "Subject: " + email_subject + "\n"
+ # MIMEText doesn't allow setting the text encoding
+ # so we use MIMENonMultipart.
+ plaintext_mime = MIMENonMultipart('text', 'plain')
+ plaintext_mime.set_payload(plaintext, charset=char_set)
if (encrypt_to_key != None):
- plaintext_reply = "thanks for the message!\n\n\n"
- plaintext_reply += email_quote_text(plaintext)
-
- # quoted printable encoding lets most ascii characters look normal
- # before the decrypted mime message is decoded.
- char_set = email.charset.Charset("utf-8")
- char_set.body_encoding = email.charset.QP
-
- # MIMEText doesn't allow setting the text encoding
- # so we use MIMENonMultipart.
- plaintext_mime = MIMENonMultipart('text', 'plain')
- plaintext_mime.set_payload(plaintext_reply, charset=char_set)
encrypted_text = encrypt_sign_message(plaintext_mime.as_string(),
encrypt_to_key,
message_mime.attach(encoded_mime)
message_mime['Content-Disposition'] = 'inline'
- reply += message_mime.as_string()
-
else:
- reply += "\n"
- reply += "Sorry, i couldn't find your key.\n"
- reply += "I'll need that to encrypt a message to you."
+ message_mime = plaintext_mime
+
+ message_mime['To'] = email_from
+ message_mime['Subject'] = email_subject
+
+ reply = message_mime.as_string()
return reply