#!/usr/bin/env python '''mailextract - Extract MIME encoded attached files from mail message SYNOPSIS mailextract [-u] source [dest] DESCRIPTION Reads mail message from source and extracts and decodes MIME attachments. If source is - then the mail message is read from stdin. If dest is not specified then the extracted files are written to stdout. dest can specify either a destination directory for extracted files or a single file name for extracted files. If dest is a directory then the extracted files will will be written to dest using the file names specified in the mail message. If dest is a file name then extracted files will be concatenated to the dest file. If the MIME attachment has no name, the -u option is specified, and dest is a directory name then the saved file names will be part_N where N is the MIME part number 1,2,.. OPTIONS --help Print this documentation. -u Include unamed MIME parts. By default only parts with a (file) name are extracted. AUTHOR Written by Stuart Rackham, COPYING Copyright (C) 2000 Stuart Rackham. Free use of this software is granted under the terms of the GNU General Public License (GPL). ''' import sys, os, string, mimetools, multifile '''Version History: 1.0 20 July 2000 Initial release. 1.0.1 22 July 2000 Added --help option. ''' VERSION = "1.0.1" error = "mailextract.error" def mailextract(src, dstfile, dstdir=None, namedonly=1): '''Read mail message from src multifile object and write attached files to dstfile file object or dstdir directory.''' headers = mimetools.Message(src, src.seekable) if headers.getmaintype() != "multipart": raise error, "message is not multipart MIME" boundary = headers.getparam("boundary") if not boundary: raise error, "message boundary not specified" partno = 0 src.push(boundary) src.read() # Read to first boundary. while not src.last: src.next() headers = mimetools.Message(src, src.seekable) partno = partno + 1 name = headers.getparam("name") if namedonly and not name: src.read() # Read to next boundary. continue encoding = headers.getencoding() if not encoding: raise error, "unknown message encoding" if dstdir: if not name: name = "part_%d" % (partno,) dstfile = open(os.path.join(dstdir,name), "wb+") else: name = os.path.basename(dstfile.name) sys.stderr.write("saving part %d (%s encoding) to %s\n" % (partno, encoding, name)) if encoding == "7bit": mimetools.copyliteral(src, dstfile) else: mimetools.decode(src, dstfile, encoding) if dstdir: dstfile.close() def usage(): cmd = os.path.basename(sys.argv[0]) sys.stderr.write("Usage: %s [-u] [--help] source [dest]\n" % cmd) def main(): # Process command line options. import getopt opts,args = getopt.getopt(sys.argv[1:],"u",["help"]) namedonly = 1 for o,v in opts: if o == '--help': print __doc__ sys.exit(0) if o == '-u': namedonly = 0 if not 1 <= len(args) <= 2: usage() sys.exit(1) if args[0] == '-': source = sys.stdin else: source = open(args[0],"rb") if len(args) > 1 and args[1] != '-': dest = args[1] else: dest = None mf = multifile.MultiFile(source, 0) if not dest: mailextract(mf, sys.stdout, namedonly=namedonly) else: if os.path.isdir(dest): mailextract(mf, None, dest, namedonly=namedonly) else: dstdir,dstfile = os.path.split(dest) if dstdir and not os.path.isdir(dstdir): raise error,"path %s not found" % dstdir f = open(dest, "wb+") mailextract(mf, f, namedonly=namedonly) f.close() source.close() if __name__ == "__main__": try: main() except (KeyboardInterrupt, SystemExit): pass except: sys.stderr.write("%s: %s\n" % (os.path.basename(sys.argv[0]), sys.exc_info()[1]))