#!/usr/bin/python2.2

# mpartinfo2hdr - version 1.0
# Written by Jarno Elonen <elonen@iki.fi>, 2003
# Released in Public Domain.


"""Usage: <message pipe> | mpartinfo2hdr
Analyze mail parts from stdin, add results to
header and write modified message stdout.

Options:

  -h or --help
    Print this message to stderr and exit WITH STATUS 2.

Header format:

  X-Msg-Part-Info: attachment; size="106496";
       md5sum="b09e26c292759d654633d3c8ed00d18d";
       claimedmime="audio/x-wav"; name="gvzvfszn.exe";
       guessedmime="application/x-dosexec"

The 'guessedmime' field is only available if the external
'file' command is installed.
"""

import getopt
import string
import email
import popen2
import zipfile
import cStringIO
import sys
import md5
import os

file_command_path = "/usr/bin/file"


try:
  opts, args = getopt.getopt(sys.argv[1:], 'h:', ['help'])
except getopt.error, msg:
  print >> sys.stderr, "ERROR: Bad arguments.\n\n", __doc__
  sys.exit(2)

for opt, arg in opts:
  if opt in ('-h', '--help'):
    print __doc__
    sys.exit(2)

try:
  msg = email.message_from_file( sys.stdin )
except KeyboardInterrupt:
  sys.exit(1)
except IOError:
  sys.stderr.write("Could not read email message from stdin\n")
  sys.exit(3)
except Exception, e:
  sys.stderr.write("mpartinfo2hdr failed: '%s'\n" % e)
  sys.exit(2)

for part in msg.walk():
  if part.is_multipart():
      continue
  filename = part.get_filename()
  claimed_mime = part.get_type()
  m = md5.new()
  pl = part.get_payload(decode=1)
  if pl == None:
    continue
  m.update(pl)

  if part.get_params(None) != None:
    for (key,val) in part.get_params():
      if key == "name":
        filename = val

  if filename == None:
    filename = ""

  guessed_mime = ""
  if os.path.exists(file_command_path):
    try:
      fps = popen2.Popen3("%s -b --mime -" % file_command_path)
      fps.tochild.write(pl)
      fps.tochild.close()
      if fps.wait() == 0:
        guessed_mime = string.strip(fps.fromchild.read())
      fps.fromchild.close()
    except:
      pass

  zip_desc = ""
  if filename.lower().rfind(".zip") == len(filename)-4:
    try:
      file_bin = cStringIO.StringIO(pl)
      zf = zipfile.ZipFile(file_bin)
      for zi in zf.infolist():
          zip_desc += ( "'%s':CRC%u " % (zi.filename, zi.CRC) )
    except:
      pass

  msg.add_header('X-Msg-Part-Info', 'partinfo', \
    name=filename, claimedmime=claimed_mime, \
    md5sum=m.hexdigest(), guessedmime=guessed_mime, \
    zipcontent=zip_desc, size="%d" % len(pl))

try:
  print >> sys.stdout, str(msg)
except:
  pass

