generate the encrypted mime reply
[edward.git] / edward
diff --git a/edward b/edward
index 9a781850919a0f984d00923cb0d645e1006c3804..21c26a13ab2b43b8725c1807d1b934827c712e63 100755 (executable)
--- a/edward
+++ b/edward
@@ -92,6 +92,9 @@ class GPGData (object):
 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
@@ -119,15 +122,15 @@ def main ():
     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):
@@ -280,10 +283,11 @@ def gpg_on_payloads (eddymsg_obj, gpgme_ctx, prev_parts=[]):
             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)
@@ -313,6 +317,7 @@ def gpg_on_payloads (eddymsg_obj, gpgme_ctx, prev_parts=[]):
                     piece.gpg_data.sigs = sig_fps
                     piece.gpg_data.plainobj = prev
                     break
+
         else:
             pass
 
@@ -321,7 +326,6 @@ def prepare_for_reply (eddymsg_obj, replyinfo_obj):
 
     do_to_eddys_pieces(prepare_for_reply_pieces, eddymsg_obj, replyinfo_obj)
 
-
 def prepare_for_reply_pieces (eddymsg_obj, replyinfo_obj):
 
     for piece in eddymsg_obj.payload_pieces:
@@ -334,9 +338,14 @@ def prepare_for_reply_pieces (eddymsg_obj, replyinfo_obj):
                 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":
@@ -352,6 +361,10 @@ def prepare_for_reply_pieces (eddymsg_obj, replyinfo_obj):
             else:
                 replyinfo_obj.sig_success = True
 
+                if replyinfo_obj.target_key == None:
+                    replyinfo_obj.fallback_target_key = piece.gpg_data.sigs[0]
+
+
 
 def flatten_payloads (eddymsg_obj):
 
@@ -366,6 +379,7 @@ def flatten_payloads (eddymsg_obj):
 
         return flat_string
 
+    # todo: don't include nested decrypted messages.
     for piece in eddymsg_obj.payload_pieces:
         if piece.piece_type == "text":
             flat_string += piece.string
@@ -380,14 +394,39 @@ def flatten_payloads (eddymsg_obj):
     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']
@@ -481,7 +520,11 @@ def decrypt_block (msg_block, gpgme_ctx):
         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):
@@ -528,23 +571,17 @@ def import_lang(email_to):
 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,
@@ -568,12 +605,13 @@ def generate_encrypted_mime (plaintext, email_from, email_subject, encrypt_to_ke
         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