#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#       Copyright 2010 Carlos Alberto Lopez Perez <clopez@igalia.com>
#
#       This program is free software; you can redistribute it and/or modify
#       it under the terms of the GNU General Public License as published by
#       the Free Software Foundation; either version 2 of the License, or
#       (at your option) any later version.
#
#       This program is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#       GNU General Public License for more details.
#
#       You should have received a copy of the GNU General Public License
#       along with this program; if not, write to the Free Software
#       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#       MA 02110-1301, USA.


########################################################################
#################                 TEMPLATES            #################
########################################################################



########################################################################
# templatestart is the head of the file. It supports the following:
########################################################################
# %(usermail)s -> is your email address
# %(usermaildotescaped)s -> is %(usermail)s but replacing '.' with '\.'
# %(username)s -> is the part before the @ of your email address
# %(userhost)s -> is the part after the @ of your email address
########################################################################
templatestart = """\
# File autogenerated using procmailgen

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin
VERBOSE=no
SHELL=/bin/bash
LOGFILE=$HOME/.procmail.log

USER=%(username)s
DELIVER="/usr/lib/dovecot/deliver -s"
MAILDIR=/var/spool/maildirs/${USER}/Maildir/
DEFAULT=${MAILDIR}

:0HB
* !? /usr/bin/spamc -c
| $DELIVER -m Spam

"""
########################################################################



########################################################################
# templatelist is for each list and folder. It supports the following:
########################################################################
# %(usermail)s -> is your email address
# %(usermaildotescaped)s -> is %(usermail)s but replacing '.' with '\.'
# %(username)s -> is the part before the @ of your email address
# %(userhost)s -> is the part after the @ of your email address
# %(folder)s -> is the folder name of your inbox for saving your emails
# %(listmail)s -> is the email of the list listname@example.com in folder
# %(listmaildotescaped)s -> is %(listmail)s but replacing '.' with '\.'
########################################################################
templatelist = """\

# Deliver list %(listmail)s to folder %(folder)s
:0w
* ^(To|Cc|X-Mailing-List|List-Id):..*%(listmaildotescaped)s\.*
| $DELIVER -m %(folder)s

"""
########################################################################



########################################################################
# templatefinish is the end of the file. It supports the following:
########################################################################
# %(usermail)s -> is your email address
# %(usermaildotescaped)s -> is %(usermail)s but replacing '.' with '\.'
# %(username)s -> is the part before the @ of your email address
# %(userhost)s -> is the part after the @ of your email address'
templatefinish = """\

# If none of the above matched the message, deliver to INBOX
:0w
| $DELIVER
"""




########################################################################
########################################################################
#################              MAIN PROGRAM            #################
########################################################################
########################################################################


import sys, os, re




def verify_valid_email(email):
    """
    Checks a string and validates it as an email address

    :type filename: string
    :param filename: An email address.


    :rtype: Boolean
    """
    if re.match("[^@]+\\@(\\[?)[a-zA-Z0-9\\-\\.\\_]+(\\]?)$", email) != None:
        # Will allow localhost names
        # and names with under_scores like microsoft ones.
        # (non-compliance with specification)
        # Usernames with spaces allowed also (RFC822)
        return True
    else:
        return False


def parse_config(filename):
    """
    Parses the configfile filename

    :type filename: string
    :param filename: The path to the file that contains the configuration.


    :rtype: { [] }
    """

    COMMENT_CHAR = '#'

    # Open the filename
    # Will not catch exceptions
    # If something wrongs happens we want the program to stop
    filelist = open(filename)

    # We will try to use orderedicts.
    # But since its only included in Python > 3.0
    # will use normal dicts if it is not availabe
    try:
        import collections as coll
        data = coll.OrderedDict()
    except:
        # Python < 3.1: use standard dictionaries
        data = dict()
    #
    #
    folder = None
    # Loop over the lines in file
    for line in filelist:
        # Strip spaces
        line = line.strip()
        # If the line that we are reading is [folder]
        if re.match("\[[^]]*\]", line):
            folder = line.strip('[]')
        elif folder != None:
            # First, remove comments:
            if COMMENT_CHAR in line:
                # Split on comment char, keep only the part before
                line, comment = line.split(COMMENT_CHAR, 1)
            # Second parse the line if is not only a comment:
            if len(line) > 0:
                # If there is no such key start a list

                # Avoid using the deprecated method dict.has_key()
                if folder not in data:
                    data[folder] = []
                # Clean it
                line = line.strip()
                # Check for valid email
                if not verify_valid_email(line):
                    raise ValueError('You have specified an incorrect '
                        'email address \'%s\' in file \'%s\' under folder \'%s\''
                         % (line, filename, folder) )
                # Appends lists to folder
                data[folder].append(line)


    # Close the file
    filelist.close()

    # Return it.
    return data


_help_message = """\

I will generate a valid procmailrc to stdout based on filename and the patterns I have.

Usage:
    %s filename your@email.com

Description:
    My purpose is to make easier configuring the deliver of mailing lists
    to the folders of your Inbox so you can keep your email organizated.


Filename:
    Filename must have a configuration like this one:

  [folder1]
  list1@example.com
  list2@example.com

  [folder2]
  list3@example.com
  list4@example.com


NOTE:
    You can easily edit me and change the generation patterns to fit your needs.
"""

def main(argv=None):
    """
    Main routine

    :type argv: []
    :param argv: argv[1] is the filename and argv[2] your email address


    :rtype: int
    """
    if argv is None:
        argv = sys.argv

    if len(argv) != 3:
        raise SystemExit(_help_message % sys.argv[0])

    if not verify_valid_email(argv[2]):
        raise SystemExit('You have specified an incorrect email address %s' % argv[2])


    usermail = argv[2].strip()
    # Split on username@userhost
    ( username, userhost ) = usermail.split('@', 1)

    if not os.access(argv[1], os.R_OK):
        raise SystemExit('I am unable to read the file %s' % argv[1])

    # Parse filename and get a dictionary with lists []
    data = parse_config(argv[1])

    if len(data) == 0:
        raise SystemExit('I cant understand your configfile: %s' % argv[1])

    # Print the head of the file
    print ( templatestart % {
           'usermail' : usermail,
           'usermaildotescaped' : usermail.replace('.','\.') ,
           'username' : username ,
           'userhost' : userhost,
            } )


    # Loop over folders
    for folder in data.keys():
        # Loop over lists in the folder
        for listmail in data[folder]:


            # Print the template for each folder and list
            print ( templatelist % {
            'usermail' : usermail,
            'usermaildotescaped' : usermail.replace('.','\.') ,
            'username' : username ,
            'userhost' : userhost,
            'listmail' : listmail ,
            'listmaildotescaped' : listmail.replace('.','\.'),
            'folder' : folder
            } )


    # Print the end of the file
    print ( templatefinish %  {
            'usermail' : usermail,
            'usermaildotescaped' : usermail.replace('.','\.') ,
            'username' : username ,
            'userhost' : userhost,
            } )

    # Program finished correctly
    return 0


# Execute main

if __name__ == '__main__':

    main()
