diff options
author | Patrick Totzke <patricktotzke@gmail.com> | 2014-08-02 17:31:44 +0200 |
---|---|---|
committer | Patrick Totzke <patricktotzke@gmail.com> | 2014-08-02 17:31:44 +0200 |
commit | 880cd37cf5104d386d82bc86b5279ba4e753baa7 (patch) | |
tree | d80fc9c459d25ddfc57735a49d80cb0951908c4a | |
parent | de18f2e4eb6d1c7af81634f1d5c27dfa4db6ec0a (diff) | |
parent | 1912b7cdedc3ffb88ba953e4e8877fdec6c38893 (diff) |
Merge branch '0.3.5-fix-forwards-682'
-rw-r--r-- | alot/commands/envelope.py | 5 | ||||
-rw-r--r-- | alot/commands/thread.py | 13 | ||||
-rw-r--r-- | alot/crypto.py | 51 | ||||
-rw-r--r-- | alot/db/envelope.py | 4 | ||||
-rw-r--r-- | alot/helper.py | 59 |
5 files changed, 71 insertions, 61 deletions
diff --git a/alot/commands/envelope.py b/alot/commands/envelope.py index b67231b7..b90816d2 100644 --- a/alot/commands/envelope.py +++ b/alot/commands/envelope.py @@ -19,6 +19,7 @@ from alot import crypto from alot.commands import Command, registerCommand from alot.commands import globals from alot.helper import string_decode +from alot.helper import email_as_string from alot.settings import settings from alot.utils.booleanaction import BooleanAction from alot.db.errors import DatabaseError @@ -130,7 +131,7 @@ class SaveCommand(Command): # store mail locally # add Date header mail['Date'] = email.Utils.formatdate(localtime=True) - path = account.store_draft_mail(crypto.email_as_string(mail)) + path = account.store_draft_mail(email_as_string(mail)) msg = 'draft saved successfully' @@ -201,7 +202,7 @@ class SendCommand(Command): try: self.mail = self.envelope.construct_mail() self.mail['Date'] = email.Utils.formatdate(localtime=True) - self.mail = crypto.email_as_string(self.mail) + self.mail = email_as_string(self.mail) except GPGProblem, e: ui.clear_notify([clearme]) ui.notify(e.message, priority='error') diff --git a/alot/commands/thread.py b/alot/commands/thread.py index f2e034f2..ca73c75f 100644 --- a/alot/commands/thread.py +++ b/alot/commands/thread.py @@ -9,6 +9,7 @@ import argparse from twisted.internet.defer import inlineCallbacks import subprocess from email.Utils import getaddresses, parseaddr +from email.message import Message import mailcap from cStringIO import StringIO @@ -30,6 +31,7 @@ from alot.db.errors import DatabaseROError from alot.settings import settings from alot.helper import parse_mailcap_nametemplate from alot.helper import split_commandstring +from alot.helper import email_as_string from alot.utils.booleanaction import BooleanAction from alot.completion import ContactsCompleter @@ -305,11 +307,16 @@ class ForwardCommand(Command): envelope.body = mailcontent + for a in self.message.get_attachments(): + envelope.attach(a) + else: # attach original mode # attach original msg - mail.set_type('message/rfc822') - mail['Content-Disposition'] = 'attachment' - envelope.attach(Attachment(mail)) + original_mail = Message() + original_mail.set_type('message/rfc822') + original_mail['Content-Disposition'] = 'attachment' + original_mail.set_payload(email_as_string(mail)) + envelope.attach(Attachment(original_mail)) # copy subject subject = decode_header(mail.get('Subject', '')) diff --git a/alot/crypto.py b/alot/crypto.py index 1270485d..4c74f1bf 100644 --- a/alot/crypto.py +++ b/alot/crypto.py @@ -4,41 +4,11 @@ import re import os -from email.generator import Generator from cStringIO import StringIO from alot.errors import GPGProblem, GPGCode -from email.mime.multipart import MIMEMultipart import gpgme -def email_as_string(mail): - """ - Converts the given message to a string, without mangling "From" lines - (like as_string() does). - - :param mail: email to convert to string - :rtype: str - """ - fp = StringIO() - g = Generator(fp, mangle_from_=False, maxheaderlen=78) - g.flatten(mail) - as_string = RFC3156_canonicalize(fp.getvalue()) - - if isinstance(mail, MIMEMultipart): - # Get the boundary for later - boundary = mail.get_boundary() - - # Workaround for http://bugs.python.org/issue14983: - # Insert a newline before the outer mail boundary so that other mail - # clients can verify the signature when sending an email which contains - # attachments. - as_string = re.sub(r'--(\r\n)--' + boundary, - '--\g<1>\g<1>--' + boundary, - as_string, flags=re.MULTILINE) - - return as_string - - def _hash_algo_name(hash_algo): """ Re-implements GPGME's hash_algo_name as long as pygpgme doesn't wrap that @@ -85,27 +55,6 @@ def RFC3156_micalg_from_algo(hash_algo): return 'pgp-' + hash_algo.lower() -def RFC3156_canonicalize(text): - """ - Canonicalizes plain text (MIME-encoded usually) according to RFC3156. - - This function works as follows (in that order): - - 1. Convert all line endings to \\\\r\\\\n (DOS line endings). - 2. Ensure the text ends with a newline (\\\\r\\\\n). - 3. Encode all occurences of "From " at the beginning of a line - to "From=20" in order to prevent other mail programs to replace - this with "> From" (to avoid MBox conflicts) and thus invalidate - the signature. - - :param text: text to canonicalize (already encoded as quoted-printable) - :rtype: str - """ - text = re.sub("\r?\n", "\r\n", text) - if not text.endswith("\r\n"): - text += "\r\n" - text = re.sub("^From ", "From=20", text, flags=re.MULTILINE) - return text def get_key(keyid, validate=False, encrypt=False, sign=False): diff --git a/alot/db/envelope.py b/alot/db/envelope.py index a9c4fc7c..6550baeb 100644 --- a/alot/db/envelope.py +++ b/alot/db/envelope.py @@ -184,7 +184,7 @@ class Envelope(object): inner_msg = textpart if self.sign: - plaintext = crypto.email_as_string(inner_msg) + plaintext = helper.email_as_string(inner_msg) logging.debug('signing plaintext: ' + plaintext) try: @@ -229,7 +229,7 @@ class Envelope(object): unencrypted_msg = inner_msg if self.encrypt: - plaintext = crypto.email_as_string(unencrypted_msg) + plaintext = helper.email_as_string(unencrypted_msg) logging.debug('encrypting plaintext: ' + plaintext) try: diff --git a/alot/helper.py b/alot/helper.py index 6eceeed9..fb95f706 100644 --- a/alot/helper.py +++ b/alot/helper.py @@ -11,16 +11,18 @@ import email import mimetypes import os import re +from email.generator import Generator from email.mime.audio import MIMEAudio from email.mime.base import MIMEBase from email.mime.image import MIMEImage from email.mime.text import MIMEText +from email.mime.multipart import MIMEMultipart import urwid import magic from twisted.internet import reactor from twisted.internet.protocol import ProcessProtocol from twisted.internet.defer import Deferred -import StringIO +from cStringIO import StringIO import logging @@ -337,8 +339,8 @@ def call_cmd_async(cmdlist, stdin=None, env=None): class _EverythingGetter(ProcessProtocol): def __init__(self, deferred): self.deferred = deferred - self.outBuf = StringIO.StringIO() - self.errBuf = StringIO.StringIO() + self.outBuf = StringIO() + self.errBuf = StringIO() self.outReceived = self.outBuf.write self.errReceived = self.errBuf.write @@ -589,3 +591,54 @@ def mailto_to_envelope(mailto_str): from alot.db.envelope import Envelope headers, body = parse_mailto(mailto_str) return Envelope(bodytext=body, headers=headers) + + +def RFC3156_canonicalize(text): + """ + Canonicalizes plain text (MIME-encoded usually) according to RFC3156. + + This function works as follows (in that order): + + 1. Convert all line endings to \\\\r\\\\n (DOS line endings). + 2. Ensure the text ends with a newline (\\\\r\\\\n). + 3. Encode all occurences of "From " at the beginning of a line + to "From=20" in order to prevent other mail programs to replace + this with "> From" (to avoid MBox conflicts) and thus invalidate + the signature. + + :param text: text to canonicalize (already encoded as quoted-printable) + :rtype: str + """ + text = re.sub("\r?\n", "\r\n", text) + if not text.endswith("\r\n"): + text += "\r\n" + text = re.sub("^From ", "From=20", text, flags=re.MULTILINE) + return text + + +def email_as_string(mail): + """ + Converts the given message to a string, without mangling "From" lines + (like as_string() does). + + :param mail: email to convert to string + :rtype: str + """ + fp = StringIO() + g = Generator(fp, mangle_from_=False, maxheaderlen=78) + g.flatten(mail) + as_string = RFC3156_canonicalize(fp.getvalue()) + + if isinstance(mail, MIMEMultipart): + # Get the boundary for later + boundary = mail.get_boundary() + + # Workaround for http://bugs.python.org/issue14983: + # Insert a newline before the outer mail boundary so that other mail + # clients can verify the signature when sending an email which contains + # attachments. + as_string = re.sub(r'--(\r\n)--' + boundary, + '--\g<1>\g<1>--' + boundary, + as_string, flags=re.MULTILINE) + + return as_string |