Add option -B to skip content-transfer-decoding binary attachments.
- Add option -O to set the destination directory.
+ Add options --save-headers, --save-body and --save-message to save decoded
+headers/bodies/messages to files.
+
+ Add option -O to set the destination directory for output files.
Fix a minor bug: if a multipart message (or a subpart) lacks any textual
content - avoid putting an excessive newline.
-WHAT'S NEW in version 2.4.0 (2014-03-08)
-
- Change option -d to accept a comma-separated list of headers:
--d h1,h2,h3,...
-
- Change option -d to decode all headers and accept a list of exceptions:
--d *,-h1,-h2,...
-
- Change option -p to accept lists of headers and parameters:
--p h1,h2,h3,..:p1,p2,p3,..
-
- Allow * and exceptions for -p in the headers and parameters lists:
--p *,-h1,-h2,-h3:p1,p2,p3
--p h1,h2,h3:*,-p1,-p2,-p3
--p *,-h1,-h2,-h3:*,-p1,-p2,-p3
-
- Change option -r to accept a list of headers: -r h1,h2,h3,...
-
- Change option -r to remove all headers and accept a list of exceptions:
--r *,-h1,-h2,...
-
- Change option -R to accept lists of headers and parameters:
--R h1,h2,h3:p1,p2,p3
--R h1,h2,h3:*,-p1,-p2,-p3
--R *,-h1,-h2,-h3:p1,p2,p3
--R *,-h1,-h2,-h3:*,-p1,-p2,-p3
-
- Publish docs in html format.
-
- Add ChangeLog.
-
-WHAT'S NEW in version 2.3.7 (2014-02-23)
-
- Add option -r to remove headers and option -R to remove headers parameters.
-
WHERE TO GET
Home page: http://phdru.name/Software/Python/#mimedecode
<arg choice="opt">
<option>-Bbeit mask</option>
</arg>
+ <arg choice="opt">
+ <option>--save-headers|body|message mask</option>
+ </arg>
<arg choice="opt">
<option>-O dest_dir</option>
</arg>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>--save-headers mask</term>
+ </varlistentry>
+
+ <varlistentry>
+ <term>--save-body mask</term>
+ </varlistentry>
+
+ <varlistentry>
+ <term>--save-message mask</term>
+ <listitem>
+ <para>
+ Append mask to a list of content types to save to a file;
+ --save-headers saves only decoded headers of the message (or
+ subpart); --save-body saves only decoded body; --save-message saves
+ the entire message (or subpart).
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term>-O dest_dir</term>
<listitem>
Initially all 4 lists are empty, so without any additional parameters
the program always uses the default decoding.
</para>
+
+<para>
+ The 3 save list options (--save-headers/body/message) are similar. They make
+ the program to save every non-multipart subpart (only headers, or body, or
+ the entire subpart) that corresponds to the given mask to a file. Before
+ saving the message (or the subpart) is decoded according to all other options
+ and placed to the output stream as usual. Filename for the file is created
+ using "filename" parameter from the Content-Disposition header, or "name"
+ parameter from the Content-Type header if one of those exist; a serial
+ counter is prepended to the filename to avoid collisions; if there are no
+ name/filename parameters, the filename is just the serial counter. The file
+ is saved in the directory set with -O (default is the current directory).
+</para>
</refsect1>
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] [-O dest_dir] [-o output_file] [input_file [output_file]]
+ 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)
if errormsg:
sys.stderr.write(errormsg + '\n')
output_headers(msg)
output(s)
+ return s
+
+
+def _save_message(msg, outstring, save_headers=False, save_body=False):
+ for header, param in (
+ ("Content-Disposition", "filename"),
+ ("Content-Type", "name"),
+ ):
+ fname = msg.get_param(param, header=header)
+ if fname:
+ fname = '-' + fname
+ break
+ else:
+ fname = ''
+ g.save_counter += 1
+ fname = str(g.save_counter) + fname
+
+ global output
+ save_output = output
+ outfile = open(os.path.join(g.destination_dir, fname), 'w')
+ output = outfile.write
+ if save_headers:
+ output_headers(msg)
+ if save_body:
+ output(outstring)
+ outfile.close()
+ output = save_output
def decode_part(msg):
for content_type in masks:
if content_type in g.totext_mask:
- totext(msg, outstring)
- return
+ outstring = totext(msg, outstring)
+ break
elif content_type in g.binary_mask or \
content_type in g.decoded_binary_mask:
output_headers(msg)
output(outstring)
- return
+ break
elif content_type in g.ignore_mask:
output_headers(msg)
output("\nMessage body of type `%s' skipped.\n" % content_type)
- return
+ break
elif content_type in g.error_mask:
raise ValueError, "content type `%s' prohibited" % content_type
+ else:
+ # Neither content type nor masks were listed - decode by default
+ outstring = totext(msg, outstring)
- # Neither content type nor masks were listed - decode by default
- totext(msg, outstring)
-
+ for content_type in masks:
+ if content_type in g.save_headers_mask:
+ _save_message(msg, outstring, save_headers=True, save_body=False)
+ elif content_type in g.save_body_mask:
+ _save_message(msg, outstring, save_headers=False, save_body=True)
+ elif content_type in g.save_message_mask:
+ _save_message(msg, outstring, save_headers=True, save_body=True)
def decode_multipart(msg):
"Decode multipart"
ignore_mask = [] # Ignore (skip, do not decode and do not include into output)
error_mask = [] # Raise error if encounter one of these
+ save_counter = 0
+ save_headers_mask = []
+ save_body_mask = []
+ save_message_mask = []
+
input_filename = None
output_filename = None
destination_dir = os.curdir
try:
options, arguments = getopt(sys.argv[1:],
'hVcCDPH:f:d:p:r:R:b:B:e:i:t:O:o:',
- ['help', 'version', 'host=', 'set-header=', 'set-param='])
+ ['help', 'version', 'host=',
+ 'save-headers=', 'save-body=', 'save-message=',
+ 'set-header=', 'set-param='])
except GetoptError:
usage(1)
g.ignore_mask.append(value)
elif option == '-e':
g.error_mask.append(value)
+ elif option == '--save-headers':
+ g.save_headers_mask.append(value)
+ elif option == '--save-body':
+ g.save_body_mask.append(value)
+ elif option == '--save-message':
+ g.save_message_mask.append(value)
elif option == '-O':
g.destination_dir = value
elif option == '-o':