#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Script takes a CSV list of users and does a 'bulk' insertion into mysql.
#
# Copyright (C) 2009 Simone Piccardi
#
# 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.
#

import csv
import getopt
import sys
import re
import time
import random, string
from datetime import datetime
from crypt import crypt
try:
    import MySQLdb 
except ImportError ,e:
    print 'Cannot import the needed MySQLdb module, you must install it'
    print 'on Debian systems just use the command'
    print '   apt-get install python-mysqldb'

def usage():
    print "Usage: inspostadmusers.py [options] users.csv"
    print "       -h        print this help"
    print "       -t        test run, do not insert, just print"
    print "       -u        DB user"
    print "       -p        DB password"
    print "       -D        DB name"
    print "       -H        DB host"
    print "       -q        Quota in Mb (0 => no limit)"
    print "       -n        char in seed"
    print "       -d        debug info on"
    print "       -A        create default alias for each domain"
    print
    print "the users.csv file must contains the user list with a line"
    print "for each user, first line should be a title line with at least"
    print "the following column names: "
    print " * user     - user part of the email (like user in user@domain.com)"
    print " * password - cleartext password"
    print " * domain   - domain name (like 'domain.com')"
    print " * name     - full user name ('Name Surname')"
    print
    print "the 'name' column is optional, other columns will be ignored"
    print
    print "Known restrictions:"
    print "* this script only works with MySQL"
    print "* mailbox paths are hardcoded to domain/username/"


# option parsing
try:
    opts, args = getopt.getopt(sys.argv[1:], 'u:p:d:D:H:htdA')
    optval={}
    for opt, val in opts:
        if opt == "-h":
            usage()
            sys.exit(0)
        else:
            optval[opt]=val
except getopt.GetoptError:
    usage()
    sys.exit(2)

#
# Setup DB connection
#
MYSQLDB="postfixadmin"
MYSQLUSER="postfixadmin"
MYSQLPASSWORD=""
MYSQLHOST="localhost"

# settings by command line options
if optval.has_key('-u'):
    MYSQLUSER = optval['-u']
if optval.has_key('-p'):
    MYSQLPASSWORD = optval['-p']
if optval.has_key('-D'):
    MYSQLDB = optval['-D']
if optval.has_key('-H'):
    MYSQLHOST = optval['-H']

if optval.has_key('-q'):
    quota = optval['-q']
else:
    quota = 0

if optval.has_key('-n'):
    seed_len = optval['-n']
else:
    seed_len = 8

# check arguments, only the user list file must be present
if len(args) !=1:
    print 'Need just one argument'
    usage()
    sys.exit(1)

# MySQL connection (skipped in test run)
if optval.has_key('-t'):
    print "Test Run"
else:
    try:
        connection = MySQLdb.connect(host=MYSQLHOST, user=MYSQLUSER, 
                                     db=MYSQLDB, passwd=MYSQLPASSWORD)
    except MySQLdb.MySQLError, e:
        print "Database connection error"
        print e
        sys.exit(1)
 
    cursor = connection.cursor()

#

# read and convert CSV data
lista = csv.DictReader(open(args[0]))

def gen_seed(seed_len, chars):
    return '$1$'+''.join([random.choice(chars) for _ in xrange(seed_len)])+'$'

def insert_record(cursor,table,record):
    columns = record.keys()
    query = "INSERT INTO " + table + "(" + ','.join(columns) + ") VALUES (" + ','.join(len(columns)*['%s']) + ")"
    try:
        cursor.execute(query, record.values())
        return 0
    except MySQLdb.MySQLError, e:
        print "Database insertion error"
        print e
        print "Record was:"
        print record.values()
        print "Query was:"
        print query

# defining default values for tables (mailbox, alias and domain)
mailbox = {
    'created': NOW, 
    'modified': NOW,
    'active': 1,
    'quota': quota
    }
aliases = {
    'created':  NOW,
    'modified': NOW,
    'active':   1
    }
domain = {
    'description': "",
    'aliases': 0,
    'mailboxes': 0,
    'quota': 0,
    'transport': 'virtual',
    'backupmx': 0,
    'created': NOW,
    'modified': NOW,
    'active': 1
}

# list of default alias
def_alias = ['abuse','hostmaster','postmaster','webmaster'] 

domain_list = {}
chars = string.letters + string.digits

# loop over the CSV 
for row in lista:
    # create domain if it does not exists
    if domain_list.has_key(row["domain"]):
        if optval.has_key('-d'):
            print "Domain " + row["domain"] + "already exixts"
    else:
        domain_list[row["domain"]] = 1
        domain['domain'] = row["domain"]
        if optval.has_key('-t'):
            print "Inserting domain"
            print domain
        else:
            insert_record(cursor,'domain',domain)
            if optval.has_key('-A'):
                for i in def_alias:
                    aliases['address']= i+'@'+row["domain"]
                    aliases['goto']= aliases['address']
                    aliases['domain'] = row["domain"]
                    if optval.has_key('-t'):
                        print "Inserting alias"
                        print aliases
                    else:
                        insert_record(cursor,'alias',aliases)

    # build query data for mailbox table
    mailbox['username']=row["user"]+'@'+row["domain"]
    encpass=crypt(row["password"], gen_seed(seed_len,chars))
    mailbox['password'] = encpass
    mailbox['name'] = row["name"]
    mailbox['maildir'] = row["domain"]+'/'+row["user"]+'/'
    mailbox['local_part'] =row["user"]
    mailbox['domain'] = row["domain"]

    # build query data for alias table
    aliases['address']= mailbox['username']
    aliases['goto']= mailbox['username']
    aliases['domain'] = row["domain"]

    # inserting data for mailbox (and relate alias)
    if optval.has_key('-t'):
        print "Inserting mailbox"
        print mailbox
        print aliases
    else:
        insert_record(cursor,'mailbox',mailbox)
        insert_record(cursor,'alias',aliases)


sys.exit(0)
# Main body
#
NOW = datetime.now().strftime("%Y-%m-%d %H:%M:%S")