]> git.phdru.name Git - mimedecode.git/blobdiff - mimedecode.py
Cleanup: Fix flake8 E701 multiple statements on one line (colon)
[mimedecode.git] / mimedecode.py
index 2fccbcc7b13f2cece51828769653bc2320257518..068394761412d2474c7b17301494a960397ee35e 100755 (executable)
@@ -1,10 +1,13 @@
 #! /usr/bin/env python
 """Decode MIME message"""
 
-import sys, os
+import os
 import subprocess
+import sys
+
 from mimedecode_version import __version__, \
     __author__, __copyright__, __license__
+
 if sys.version_info[0] >= 3:
     # Replace email.message._formatparam with _formatparam from Python 2.7
     # to avoid re-encoding non-ascii params.
@@ -17,13 +20,15 @@ def version(exit=1):
     sys.stdout.write("""\
 Broytman mimedecode.py version %s, %s
 """ % (__version__, __copyright__))
-    if exit: sys.exit(0)
+    if exit:
+        sys.exit(0)
+
 
 def usage(code=0, errormsg=''):
     version(0)
     sys.stdout.write("""\
 Usage: %s [-h|--help] [-V|--version] [-cCDP] [-H|--host=hostname] [-f charset] [-d header1[,h2,...]|*[,-h1,...]] [-p header1[,h2,h3,...]:param1[,p2,p3,...]] [-r header1[,h2,...]|*[,-h1,...]] [-R header1[,h2,h3,...]:param1[,p2,p3,...]] [--set-header header:value] [--set-param header:param=value] [-Bbeit mask] [--save-headers|body|message mask] [-O dest_dir] [-o output_file] [input_file [output_file]]
-""" % me)
+""" % me)  # noqa: E501
     if errormsg:
         sys.stderr.write(errormsg + os.linesep)
     sys.exit(code)
@@ -43,16 +48,16 @@ def output_headers(msg):
             output(";")
             output(_decode_header(value[1], strip=False))
         output(os.linesep)
-    output(os.linesep) # End of headers
+    output(os.linesep)  # End of headers
 
 
 def recode_if_needed(s, charset):
-    if bytes is str: # Python2
+    if bytes is str:  # Python2
         if isinstance(s, bytes) and \
                 charset and charset.lower() != g.default_encoding:
             s = s.decode(charset, "replace").\
                 encode(g.default_encoding, "replace")
-    else: # Python3
+    else:  # Python3
         if isinstance(s, bytes):
             s = s.decode(charset, "replace")
     return s
@@ -80,19 +85,23 @@ def _decode_header(s, strip=True):
     # together into the final string.
     return ' '.join(rtn)
 
+
 def decode_header(msg, header):
     "Decode mail header (if exists) and put it back, if it was encoded"
 
     if header in msg:
         value = msg[header]
         new_value = _decode_header(value)
-        if new_value != value: # do not bother to touch msg if not changed
+        if new_value != value:  # do not bother to touch msg if not changed
             set_header(msg, header, new_value)
 
 
 def decode_header_param(msg, header, param):
-    "Decode mail header's parameter (if exists) and put it back, if it was encoded"
+    """Decode mail header's parameter
 
+    Decode mail header's parameter (if exists)
+    and put it back if it was encoded.
+    """
     if header in msg:
         value = msg.get_param(param, header=header)
         if value:
@@ -100,12 +109,13 @@ def decode_header_param(msg, header, param):
                 new_value = recode_if_needed(value[2], value[0])
             else:
                 new_value = _decode_header(value)
-            if new_value != value: # do not bother to touch msg if not changed
+            if new_value != value:  # do not bother to touch msg if not changed
                 msg.set_param(param, new_value, header)
 
 
 def _get_exceptions(list):
-    return [x[1:].lower() for x in list[1:] if x[0]=='-']
+    return [x[1:].lower() for x in list[1:] if x[0] == '-']
+
 
 def _decode_headers_params(msg, header, decode_all_params, param_list):
     if decode_all_params:
@@ -118,6 +128,7 @@ def _decode_headers_params(msg, header, decode_all_params, param_list):
         for param in param_list:
             decode_header_param(msg, header, param)
 
+
 def _remove_headers_params(msg, header, remove_all_params, param_list):
     if remove_all_params:
         params = msg.get_params(header=header)
@@ -128,71 +139,78 @@ def _remove_headers_params(msg, header, remove_all_params, param_list):
                         msg.del_param(param, header)
             else:
                 value = msg[header]
-                if value is None: # No such header
+                if value is None:  # No such header
                     return
-                if ';' not in value: # There are no parameters
+                if ';' not in value:  # There are no parameters
                     return
-                del msg[header] # Delete all such headers
+                del msg[header]  # Delete all such headers
                 # Get the value without parameters and set it back
                 msg[header] = value.split(';')[0].strip()
     else:
         for param in param_list:
             msg.del_param(param, header)
 
+
 def decode_headers(msg):
     "Decode message headers according to global options"
 
     for header_list in g.remove_headers:
         header_list = header_list.split(',')
-        if header_list[0] == '*': # Remove all headers except listed
+        if header_list[0] == '*':  # Remove all headers except listed
             header_list = _get_exceptions(header_list)
             for header in msg.keys():
                 if header.lower() not in header_list:
                     del msg[header]
-        else: # Remove listed headers
+        else:  # Remove listed headers
             for header in header_list:
                 del msg[header]
 
     for header_list, param_list in g.remove_headers_params:
         header_list = header_list.split(',')
         param_list = param_list.split(',')
-        remove_all_params = param_list[0] == '*' # Remove all params except listed
+        # Remove all params except listed.
+        remove_all_params = param_list[0] == '*'
         if remove_all_params:
             param_list = _get_exceptions(param_list)
-        if header_list[0] == '*': # Remove for all headers except listed
+        if header_list[0] == '*':  # Remove for all headers except listed
             header_list = _get_exceptions(header_list)
             for header in msg.keys():
                 if header.lower() not in header_list:
-                    _remove_headers_params(msg, header, remove_all_params, param_list)
-        else: # Decode for listed headers
+                    _remove_headers_params(
+                        msg, header, remove_all_params, param_list)
+        else:  # Decode for listed headers
             for header in header_list:
-                _remove_headers_params(msg, header, remove_all_params, param_list)
+                _remove_headers_params(
+                    msg, header, remove_all_params, param_list)
 
     for header_list in g.decode_headers:
         header_list = header_list.split(',')
-        if header_list[0] == '*': # Decode all headers except listed
+        if header_list[0] == '*':  # Decode all headers except listed
             header_list = _get_exceptions(header_list)
             for header in msg.keys():
                 if header.lower() not in header_list:
                     decode_header(msg, header)
-        else: # Decode listed headers
+        else:  # Decode listed headers
             for header in header_list:
                 decode_header(msg, header)
 
     for header_list, param_list in g.decode_header_params:
         header_list = header_list.split(',')
         param_list = param_list.split(',')
-        decode_all_params = param_list[0] == '*' # Decode all params except listed
+        # Decode all params except listed.
+        decode_all_params = param_list[0] == '*'
         if decode_all_params:
             param_list = _get_exceptions(param_list)
-        if header_list[0] == '*': # Decode for all headers except listed
+        if header_list[0] == '*':  # Decode for all headers except listed
             header_list = _get_exceptions(header_list)
             for header in msg.keys():
                 if header.lower() not in header_list:
-                    _decode_headers_params(msg, header, decode_all_params, param_list)
-        else: # Decode for listed headers
+                    _decode_headers_params(
+                        msg, header, decode_all_params, param_list)
+        else:  # Decode for listed headers
             for header in header_list:
-                _decode_headers_params(msg, header, decode_all_params, param_list)
+                _decode_headers_params(
+                    msg, header, decode_all_params, param_list)
 
 
 def set_header(msg, header, value):
@@ -211,12 +229,14 @@ def set_content_type(msg, newtype, charset=None):
         msg.set_param("charset", charset, "Content-Type")
 
 
-caps = None # Globally stored mailcap database; initialized only if needed
+caps = None  # Globally stored mailcap database; initialized only if needed
+
 
 def decode_body(msg, s):
     "Decode body to plain text using first copiousoutput filter from mailcap"
 
-    import mailcap, tempfile
+    import mailcap
+    import tempfile
 
     global caps
     if caps is None:
@@ -254,16 +274,20 @@ def decode_body(msg, s):
     pipe = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
     new_s = pipe.stdout.read()
     pipe.stdout.close()
-    if pipe.wait() == 0: # result=0, Ok
+    if pipe.wait() == 0:  # result=0, Ok
         s = new_s
         if bytes is not str and isinstance(s, bytes):  # Python3
             s = s.decode(g.default_encoding, "replace")
         if charset and not isinstance(s, bytes):
             s = s.encode(charset, "replace")
         set_content_type(msg, "text/plain")
-        msg["X-MIME-Autoconverted"] = "from %s to text/plain by %s id %s" % (content_type, g.host_name, command.split()[0])
+        msg["X-MIME-Autoconverted"] = \
+            "from %s to text/plain by %s id %s" \
+            % (content_type, g.host_name, command.split()[0])
     else:
-        msg["X-MIME-Autoconverted"] = "failed conversion from %s to text/plain by %s id %s" % (content_type, g.host_name, command.split()[0])
+        msg["X-MIME-Autoconverted"] = \
+            "failed conversion from %s to text/plain by %s id %s" \
+            % (content_type, g.host_name, command.split()[0])
     os.remove(filename)
 
     return s
@@ -277,7 +301,9 @@ def recode_charset(msg, s):
         s = recode_if_needed(s, charset)
         content_type = msg.get_content_type()
         set_content_type(msg, content_type, g.default_encoding)
-        msg["X-MIME-Autoconverted"] = "from %s to %s by %s id %s" % (save_charset, g.default_encoding, g.host_name, me)
+        msg["X-MIME-Autoconverted"] = \
+            "from %s to %s by %s id %s" \
+            % (save_charset, g.default_encoding, g.host_name, me)
     return s
 
 
@@ -296,6 +322,7 @@ def totext(msg, instring):
 
 mimetypes = None
 
+
 def _guess_extension(ctype):
     global mimetypes
     if mimetypes is None:
@@ -306,6 +333,7 @@ def _guess_extension(ctype):
             mimetypes._db.read(user_mime_type)
     return mimetypes.guess_extension(ctype)
 
+
 def _save_message(msg, outstring, save_headers=False, save_body=False):
     for header, param in (
         ("Content-Disposition", "filename"),
@@ -314,7 +342,7 @@ def _save_message(msg, outstring, save_headers=False, save_body=False):
         fname = msg.get_param(param, header=header)
         if fname:
             if isinstance(fname, tuple):
-                fname = fname[2] # Do not recode if it isn't recoded yet
+                fname = fname[2]  # Do not recode if it isn't recoded yet
             try:
                     for forbidden in chr(0), '/', '\\':
                         if forbidden in fname:
@@ -329,15 +357,18 @@ def _save_message(msg, outstring, save_headers=False, save_body=False):
     fname = str(g.save_counter) + fname
     if '.' not in fname:
         ext = _guess_extension(msg.get_content_type())
-        if ext: fname += ext
+        if ext:
+            fname += ext
 
     global output
     save_output = output
     outfile = open_output_file(fname)
+
     def _output_bytes(s):
         if not isinstance(s, bytes):
             s = s.encode(g.default_encoding, "replace")
         outfile.write(s)
+
     output = _output_bytes
     if save_headers:
         output_headers(msg)
@@ -375,10 +406,11 @@ def decode_part(msg):
     encoding = msg["Content-Transfer-Encoding"]
     if left_binary or encoding in (None, '', '7bit', '8bit', 'binary'):
         outstring = msg.get_payload()
-    else: # Decode from transfer ecoding to text or binary form
+    else:  # Decode from transfer ecoding to text or binary form
         outstring = msg.get_payload(decode=1)
         set_header(msg, "Content-Transfer-Encoding", "8bit")
-        msg["X-MIME-Autoconverted"] = "from %s to 8bit by %s id %s" % (encoding, g.host_name, me)
+        msg["X-MIME-Autoconverted"] = \
+            "from %s to 8bit by %s id %s" % (encoding, g.host_name, me)
 
     for content_type in masks:
         if content_type in g.totext_mask:
@@ -391,7 +423,8 @@ def decode_part(msg):
             break
         elif content_type in g.ignore_mask:
             output_headers(msg)
-            output("%sMessage body of type %s skipped.%s" % (os.linesep, ctype, os.linesep))
+            output("%sMessage body of type %s skipped.%s"
+                   % (os.linesep, ctype, os.linesep))
             break
         elif content_type in g.error_mask:
             break
@@ -411,6 +444,7 @@ def decode_part(msg):
         if content_type in g.error_mask:
             raise ValueError("content type %s prohibited" % ctype)
 
+
 def decode_multipart(msg):
     "Decode multipart"
 
@@ -430,7 +464,8 @@ def decode_multipart(msg):
             return
         elif content_type in g.ignore_mask:
             output_headers(msg)
-            output("%sMessage body of type %s skipped.%s" % (os.linesep, ctype, os.linesep))
+            output("%sMessage body of type %s skipped.%s"
+                   % (os.linesep, ctype, os.linesep))
             if boundary:
                 output("%s--%s--%s" % (os.linesep, boundary, os.linesep))
             return
@@ -467,8 +502,10 @@ def decode_multipart(msg):
 
     output_headers(msg)
 
-    if msg.preamble: # Preserve the first part, it is probably not a RFC822-message
-        output(msg.preamble) # Usually it is just a few lines of text (MIME warning)
+    # Preserve the first part, it is probably not a RFC822-message.
+    if msg.preamble:
+        # Usually it is just a few lines of text (MIME warning).
+        output(msg.preamble)
     if msg.preamble is not None:
         output(os.linesep)
 
@@ -496,9 +533,9 @@ def decode_message(msg):
 
     if msg.is_multipart():
         decode_multipart(msg)
-    elif len(msg): # Simple one-part message (there are headers) - decode it
+    elif len(msg):  # Simple one-part message (there are headers) - decode it
         decode_part(msg)
-    else: # Not a message, just text - copy it literally
+    else:  # Not a message, just text - copy it literally
         output(msg.as_string())
 
 
@@ -517,7 +554,7 @@ def open_output_file(filename):
 
 class GlobalOptions:
     from m_lib.defenc import default_encoding
-    recode_charset = 1 # recode charset of message body
+    recode_charset = 1  # recode charset of message body
 
     host_name = None
 
@@ -541,11 +578,15 @@ class GlobalOptions:
     # A list of header/parameter/value triples to set
     set_header_param = []
 
-    totext_mask = [] # A list of content-types to decode
-    binary_mask = [] # A list of content-types to pass through
-    decoded_binary_mask = [] # A list of content-types to pass through (content-transfer-decoded)
-    ignore_mask = [] # Ignore (do not decode and do not include into output) but output a warning instead of the body
-    fully_ignore_mask = [] # Completely ignore - no headers, no body, no warning
+    totext_mask = []  # A list of content-types to decode
+    binary_mask = []  # A list of content-types to pass through
+    # A list of content-types to pass through (content-transfer-decoded).
+    decoded_binary_mask = []
+    # Ignore (do not decode and do not include into output)
+    # but output a warning instead of the body.
+    ignore_mask = []
+    # Completely ignore - no headers, no body, no warning.
+    fully_ignore_mask = []
     error_mask = []  # Raise error if encounter one of these
 
     save_counter = 0
@@ -557,6 +598,7 @@ class GlobalOptions:
     output_filename = None
     destination_dir = os.curdir
 
+
 g = GlobalOptions