summaryrefslogtreecommitdiff
path: root/alot/helper.py
diff options
context:
space:
mode:
authorYann Rouillard <yann@pleiades.fr.eu.org>2013-12-08 17:40:33 +0100
committerPatrick Totzke <patricktotzke@gmail.com>2014-08-02 17:29:33 +0200
commit1912b7cdedc3ffb88ba953e4e8877fdec6c38893 (patch)
treed80fc9c459d25ddfc57735a49d80cb0951908c4a /alot/helper.py
parent6e1990f019fee1cf01af1c63e6f18607da672296 (diff)
Move email_as_string function from crypto to helper module
The email_as_string function, and the related RFC3156_canonicalize function, are now used by the ForwardCommand and are not specific anymore to the crypto routine. So we move them to the global helper module. fix an import removal mistake while moving email_as_string function: StringIO was not only used by email_as_string
Diffstat (limited to 'alot/helper.py')
-rw-r--r--alot/helper.py59
1 files changed, 56 insertions, 3 deletions
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