#! /usr/bin/python

import sys, os, os.path, pwd, string, StringIO, time
import rfc822, socket


class MailDestiny:

    def __init__(self, destinyname=""):
        self.destinyname = destinyname


class DevNull(MailDestiny):
    "send mail to /dev/null"

    def __init__(self):
        pass

    def getfd(self):
        self.fd = open("/dev/null", "a")
        return self.fd

    def closefd(self):
        self.fd.close


class Pipe(MailDestiny):
    "send mail to another program - headers included"

    def getfd(self):
        self.fd = os.popen(self.destinyname, "w")
        return self.fd

    def closefd(self):
        self.fd.close


class MailForward(MailDestiny):
    "forward mail to another address"

    def getfd(self):
        self.fd = os.popen(sendmailbin+" "+self.destinyname, "w")
        return self.fd

    def closefd(self):
        self.fd.close


class MailDir(MailDestiny):
    "deliver mail to a maildir directory"

    def filename(self):
        return `long(time.time())`[:-1]+"."+`os.getpid()`+"."+socket.gethostname()

    def getfd(self):
        self.name = self.filename()
        while os.path.isfile(self.name):
            time.sleep(2)
        try:
            os.makedirs (self.destinyname+"/tmp", 0700)
            os.makedirs (self.destinyname+"/cur", 0700)
            os.makedirs (self.destinyname+"/new", 0700)
        except:
            pass
        os.umask(077)
        self.fd=open(self.destinyname+"/tmp/"+self.name,"a")
        return self.fd

    def closefd(self):
        self.fd.close()
        os.link(self.destinyname+"/tmp/"+self.name, self.destinyname+"/new/"+self.name)
        os.unlink(self.destinyname+"/tmp/"+self.name)


class MailBox(MailDestiny):
    "deliver mail to BSD mail folder - you need lockfile (from procmail package) for locking to work!"

    def lock(self):
        if self.destinyname == defaultbox:
            os.system(lockfilebin+" -ml")
        else:
            os.system(lockfilebin+" "+self.destinyname+".lock")

    def unlock(self):
        if self.destinyname == defaultbox:
            os.system(lockfilebin+" -mu")
        else:
            os.unlink(self.destinyname+".lock")

    def locked(self):
        return os.path.isfile(self.destinyname+".lock")

    def filename(self):
        return self.destinyname

    def getfd(self):
        self.lock()
        self.name = self.filename()
        os.umask(077)
        self.fd=open(self.name,"a")
        return self.fd

    def closefd(self):
        self.fd.close
        self.unlock()


def stop():
    raise "stop_of_pycmailrc"

def contains(s, sub, case=1):
    "return the same as string.count, but s can be None, and you can specify case-insensitivity"
    if case:
        return string.count(s or "", sub)
    else:
        return string.count(string.lower(s or ""), string.lower(sub))

def isinheader(hname, sub, case=1):
    "return true if sub is in header with name hname"
    return contains(mailmsg.getheader(hname), sub, case)

def untuple(list):
    "change list of tuples into tuple of lists"
    return map(lambda x: x[0], list), map(lambda x: x[1], list)


username = pwd.getpwuid(os.getuid())[0]
userhome = pwd.getpwuid(os.getuid())[5]
defaultbox = "/var/spool/mail/"+username
default = MailBox(defaultbox)
initbufsize = 8192
bufsize = 4096

sendmailbin = "/usr/sbin/sendmail"
lockfilebin = "/usr/bin/lockfile"

destination = []


try:
    if os.path.isfile("/etc/pycmailrc"):
        execfile("/etc/pycmailrc")


    stdin = sys.stdin
    msg = stdin.read(initbufsize)
    msgIO = StringIO.StringIO(msg)
    mailmsg = rfc822.Message(msgIO)
    FROM = mailmsg.getheader('From') or ""
    TO = mailmsg.getheader('To') or ""
    CC = mailmsg.getheader('Cc') or ""
    SUBJECT = mailmsg.getheader('Subject') or ""
    ADDR_FROM = mailmsg.getaddr('From')
    ADDR_TO = mailmsg.getaddr('To')
    ADDR_CC = mailmsg.getaddr('Cc')
    NAMELIST_TO, ADDRLIST_TO = untuple(mailmsg.getaddrlist('To'))
    NAMELIST_CC, ADDRLIST_CC = untuple(mailmsg.getaddrlist('Cc'))
    mailmsg.rewindbody()
    BODY = msgIO.readlines()
    msgIO.close()

    try:
        if os.path.isfile(userhome+"/.pycmailrc"):
            execfile(userhome+"/.pycmailrc")
    except "stop_of_pycmailrc":  #used to simulate a goto command
        pass

    if destination == []:
        destination = [default]

    destfd = []
    for i in destination:
        fd = i.getfd()
        fd.write(msg)
        destfd.append(fd)

    while 1:
        msg = stdin.read(bufsize)
        if msg == "": break
        for i in destfd:
            i.write(msg)

finally:
    for i in destination:
        try:
            i.closefd()
        except:
            pass

