#!/usr/bin/env python

######################
# Sender (client) mode
######################

"""Tag and send outgoing messages.

Usage:  %(program)s [-c <file>] [-f <sender>] [-q] [-h] [ recip ... ]

Where:
	-c <file>
	--config-file <file>
	   Specify a different configuration file other than ~/.tmdarc.

        -f <sender>
           This option is silently ignored currently.

        -q
        --qfilter
           Return 99 to qfilter so it will not run qmail-queue itself.

	--help
	-h
	   Print this help message and exit.
	   
	recip
	   If one or more recipients are provided, send the message to
	   all recip arguments.  If none are provided, send the message
	   to all header recipient addresses.
"""

import getopt
import os
import popen2
import rfc822
import string
import sys


# The contents of these two lists will be used to tag the message.
envelope_sender_address = []
sender_full_name = []

program = sys.argv[0]
qfilter = None

def usage(code, msg=''):
    print __doc__ % globals()
    if msg:
        print msg
    sys.exit(code)
    
try:
    opts, args = getopt.getopt(sys.argv[1:],
                               'c:qhf:', ['config-file=','qfilter','help'])
except getopt.error, msg:
    usage(1, msg)

for opt, arg in opts:
    if opt in ('-h', '--help'):
        usage(0)
    elif opt in ('-c', '--config-file'):
        os.environ['TMDARC'] = arg
    elif opt in ('-q', '--qfilter'):
        qfilter = 99
    elif opt == '-f':
        pass


try:
    import paths
except ImportError:
    pass

from TMDA import Cookie
from TMDA import Defaults
from TMDA import Util


message = sys.stdin
message_headers = rfc822.Message(message)


def inject_message(to_address,
                   from_address,
                   message_headers,
                   message_body,
                   cookie_type,
                   extension=None):
    """Hand the message off to sendmail."""
    if cookie_type == 'bare':
        # Send a message with an untagged address.
        envelope_sender_address.append(from_address)
    elif cookie_type == 'dated':
        # Send a message with a tagged (dated) address.
        envelope_sender_address.append(Cookie.make_dated_address(from_address))
    elif cookie_type == 'sender':
        # Send a message with a tagged (sender) address
        envelope_sender_address.append(Cookie.make_sender_address
                                       (from_address, to_address))
    elif cookie_type == 'exp':
        # Send a message with an explicitly defined address.
        envelope_sender_address.append(from_address)
    elif cookie_type == 'ext':
        # Send a message with a tagged (extension added) address.
        (username, hostname) = string.split(from_address,'@')
        envelope_sender_address.append(username + Defaults.RECIPIENT_DELIMITER
                                       + extension + '@' + hostname)
    elif cookie_type == 'keyword':
        # Send a message with a tagged (keyword) address.
        envelope_sender_address.append(Cookie.make_keyword_address
                                       (from_address, extension))
    # Set From: to match the envelope sender address.
    final_sender_address = envelope_sender_address[-1:][0]
    final_full_name = sender_full_name[0]
    if Defaults.MESSAGE_FROM_STYLE == 'angles':
        message_from_format = '"%s" <%s>' % (final_full_name,final_sender_address)
    elif Defaults.MESSAGE_FROM_STYLE == 'parens':
        message_from_format = '%s (%s)' % (final_sender_address,final_full_name)
    elif Defaults.MESSAGE_FROM_STYLE == 'address':
         message_from_format = '%s' % (final_sender_address)
    message_headers['From'] = message_from_format
    # Inject the message.
    inject = []
    inject.append(Defaults.SENDMAIL)
    inject.append('-f')
    inject.append(final_sender_address)
    inject.append(to_address)
    pipeline = popen2.popen2(inject)[1]
    pipeline.write(str(message_headers))
    pipeline.write('\n')
    pipeline.write(message_body)
    pipeline.close()


######
# Main
######

def main():

    x_tmda_over = None
    exp_from_address = None
    ext_extension = None
    keyword_extension = None

    # Use the existing From: header if possible.
    (fullname, from_address) = message_headers.getaddr("from")
    if fullname:
        sender_full_name.append(fullname)
    else:
        sender_full_name.append(Defaults.FULLNAME)
    if not from_address or len(string.split(from_address,'@')) != 2:
        from_address = Defaults.USERNAME + '@' + Defaults.HOSTNAME
    
    header_to = message_headers.getaddrlist("to")
    header_cc = message_headers.getaddrlist("cc")
    header_bcc = message_headers.getaddrlist("bcc")
    # Add custom headers.
    message_headers['X-Delivery-Agent'] = Defaults.DELIVERY_AGENT
    # Read in the message body.
    message_body = message.read()
    
    # If recipients were provided as args, use them.
    if args:
        address_list = args
    # If running through qfilter, get recipient list from QMAILRCPTS.
    elif os.environ.has_key('QMAILRCPTS'):
        address_list = string.split(string.lower
                                    (os.environ['QMAILRCPTS']),'\n')[:-1]
    else:
        # Combine To:, Cc:, and Bcc: addresses into one list.
	address_list = []
	for list in header_to,header_cc,header_bcc:
	    for a in list:
                address = a[1]
                address_list.append(address)
               
    # Check for the `X-TMDA' override header.
    if message_headers.has_key('x-tmda'):
        x_tmda_over = 1
        x_tmda = message_headers.getheader('x-tmda')
        fields = string.split(x_tmda)
        tagtype = string.lower(fields[0])
        if tagtype == 'dated':
            address_cookie = tagtype
            try:                        # check for timeout override
                os.environ['TMDA_TIMEOUT'] =  fields[1]
            except IndexError:
                pass
        elif tagtype in ('bare','sender'):
            address_cookie = tagtype
        elif tagtype in ('exp','explicit'):
            address_cookie = 'exp'
            exp_from_address = fields[1]
        elif tagtype in ('ext','extension'):
            address_cookie = 'ext'
            ext_extension = fields[1]
        elif tagtype in ('kw','keyword'):
            address_cookie = 'keyword'
            keyword_extension = fields[1]
        else:
            pass
        # Delete `X-TMDA' before sending.
        del message_headers['x-tmda']
    else:
        # Without `X-TMDA', we need to process the special-case files.
        bare_list = []
        if os.path.exists(Defaults.BARE_FILE):
            bare_list = Util.file_to_list(Defaults.BARE_FILE,bare_list)
        if Defaults.WHITELIST_TO_BARE and os.path.exists(Defaults.WHITELIST):
            bare_list = Util.file_to_list(Defaults.WHITELIST,bare_list)

        dated_list = []
        if os.path.exists(Defaults.DATED_FILE):
            dated_list = Util.file_to_list(Defaults.DATED_FILE,dated_list)

        sender_list = []
        if os.path.exists(Defaults.SENDER_FILE):
            sender_list = Util.file_to_list(Defaults.SENDER_FILE,sender_list)

        keyword_list = []
        if os.path.exists(Defaults.KEYWORD_FILE):
            keyword_list = Util.file_to_list(Defaults.KEYWORD_FILE,keyword_list)

        exp_list = []
        if os.path.exists(Defaults.EXP_FILE):
            exp_list = Util.file_to_list(Defaults.EXP_FILE,exp_list)
    
        ext_list = []
        if os.path.exists(Defaults.EXT_FILE):
            ext_list = Util.file_to_list(Defaults.EXT_FILE,ext_list)

    # If the address matches a special case, it is tagged accordingly,
    # otherwise it is tagged with the default cookie type.
    for address in address_list:
        # If `X-TMDA' is present we are done here.
        if x_tmda_over:
            pass                        

        elif Util.findmatch(bare_list,address):
            address_cookie = 'bare'

        elif Util.findmatch(dated_list,address):
            address_cookie = 'dated'
                    
        elif Util.findmatch(sender_list,address):
            address_cookie = 'sender'

        else:
            exp_match = Util.findmatch(exp_list,address)
            ext_match = Util.findmatch(ext_list,address)
            keyword_match = Util.findmatch(keyword_list,address)
            if exp_match:
                address_cookie = 'exp'
                if not exp_from_address:exp_from_address = exp_match
            elif ext_match:
                address_cookie = 'ext'
                if not ext_extension:ext_extension = ext_match
            elif keyword_match:
                address_cookie = 'keyword'
                if not keyword_extension:keyword_extension = keyword_match
            else:
                address_cookie = Defaults.COOKIE_TYPE

        # The message is sent to each recipient separately so that
        # everyone gets the correct tag.  Make sure your MUA
        # generates its own Message-ID: and Date: headers so they
        # match on multiple recipient messages.
        if address_cookie == 'bare':
            inject_message(address,
                           from_address,
                           message_headers,
                           message_body,
                           address_cookie)
        elif address_cookie == 'dated':
            inject_message(address,
                           from_address,
                           message_headers,
                           message_body,
                           address_cookie)
        elif address_cookie == 'sender':
            inject_message(address,
                           from_address,
                           message_headers,
                           message_body,
                           address_cookie)
        elif address_cookie == 'exp':
            inject_message(address,
                           exp_from_address,
                           message_headers,
                           message_body,
                           address_cookie)
        elif address_cookie == 'ext':
            inject_message(address,
                           from_address,
                           message_headers,
                           message_body,
                           address_cookie,
                           ext_extension)
        elif address_cookie == 'keyword':
            inject_message(address,
                           from_address,
                           message_headers,
                           message_body,
                           address_cookie,
                           keyword_extension)
        else:
            print "Unknown cookie type:",address_cookie
            sys.exit(Defaults.EX_TEMPFAIL)

    if qfilter:
        sys.exit(qfilter)
    else:
        sys.exit(Defaults.EX_OK)


# This is the end my friend.
if __name__ == '__main__':
    main()
