#!/opt/osstech/bin/python2.7
# -*- coding: utf-8 -*-

# googleapps-account-csvuseradd.py 
# - Account create to Google Apps by reading CSV file
#
# Copyright (C) TAKEDA Yasuma @ Open Source Solution Technology Co. Ltd.
# License: GNU General Public License version 2 or later
# Date: 2009-09-24, since 2009-03-13

import os, sys, csv, datetime, getopt, string, sha, binascii

# from Google
import gdata.apps.service
import gdata.apps.emailsettings.service

# from OSSTech
import googleappsutils.domain


# Command Option
# -d domain name of Google Apps(Must)
# -f csv file(Must)
# -l directory of result file
# -s directory of summary file

# CSV Format
# This file must be UTF-8 encoding.
# |username|  sn  |givenName|password|
# |user1   |Yamada|Taro     |secret  |
# |user2   |Suzuki|Ichiro   |secret2 |


def usage():
    sys.stderr.write("Usage:" + sys.argv[0] + " -d domain -f csvfile [-l resultfile] [-s summaryfile]\n")
    sys.exit(1)

def isYes(str):
    if string.upper(str) == "YES":
        return True
    return False

def main():
    domain = None
    csvfile = None
    resultfile = None
    summaryfile = None
    password_hash = None

    # Parse option
    try:
        (opts, args) = getopt.getopt(sys.argv[1:], "d:f:l:s:")
    except getopt.GetoptError:
        sys.stderr.write("Error : Invalid Option\n")
        usage()

    for (opt, value) in opts:
        if opt == "-d":
            domain = value
        if opt == "-f":
            csvfile = value
        if opt == "-l":
            resultfile = value
        if opt == "-s":
            summaryfile = value

    if domain == None or csvfile == None:
        usage()

    # try to open csv file.
    try:
        csvFd = open(csvfile, 'r')
    except Exception, e:
        sys.stderr.write("Error : Failed to open csvfile.\n")
        sys.stderr.write(str(e) + "\n")
        sys.exit(1)

    # Read Configuration
    gDomain = googleappsutils.domain.Domain()
    try:
        gDomain.readConfig(domain)
    except Exception, e:
        sys.stderr.write("Error : Invalid configuration [" + domain + "]\n")
        sys.stderr.write(str(e))
        sys.exit(1)

    # Setup result files
    type = "useradd"
    now = datetime.datetime.now()    
    baseFileName = gDomain.getBaseFilename(now, type, domain)
    if resultfile == None:
        resultfile = gDomain.resultDir + baseFileName + "-result.csv"
    if summaryfile == None:
        summaryfile = gDomain.summaryDir + baseFileName + ".summary"

    try:
        resultFd = open(resultfile, "w")
        summaryFd = open(summaryfile, "w")
    except Exception, e:
        sys.stderr.write("Error : Failed to open file.\n")
        sys.stderr.write(str(e))
        sys.exit(1)

    # Password Hash Type
    password_hash = gDomain.getPasswordHash()

    # Read entries from csv file
    try:
        reader = csv.reader(csvFd)
    except Exception , e:
        sys.stderr.write("Error : Failed to read entry from csv file.\n")
        sys.stderr.write(str(e)+"\n")
        sys.exit(1)
    
    # Connect to Google Apps
    try:
        service = gdata.apps.service.AppsService(gDomain.admin,gDomain.adminPass, gDomain.domain)
        service.ProgrammaticLogin()
        emailsettings = gdata.apps.emailsettings.service.EmailSettingsService(gDomain.admin, gDomain.adminPass,gDomain.domain)
        emailsettings.ProgrammaticLogin()
    except Exception, e:
        sys.stderr.write("Error : Failed to connect to Google Apps.\n" + str(e) + "\n")
        sys.exit(1)

    # Handle each entries
    r = 0 # counter of row. 0 is header
    header = []
    error = 0
    success = 0
    for row in reader:
        username = None
        pop = gDomain.popEnable
        imap = gDomain.imapEnable
        if len(row) == 0:
            continue

        if r == 0:
            # Create header list
            for key in row:
                header.append(key)
            # Check sn,giveName,password is included in headerAttrs.
            headerAttrs = set(header)
            if ("sn" not in headerAttrs) or ("givenName" not in headerAttrs) or ("password" not in headerAttrs):
                sys.stderr.write("Error : Invalid csv format.\n")
                sys.exit(1)
        else:
            # Create user entry
            attrs = {}
            n = 0
            for value in row:
                if n == 0:
                    username = value
                else:
                    attrs[header[n]] = value
                n = n + 1

            # Check sn,givenName,password is included in attrs.
            if (not attrs.has_key("sn")) or (not attrs.has_key("givenName")) or (not attrs.has_key("password")):
                errormsg = username + ",Some attributes are missing\n"
                sys.stderr.write(errormsg)
                resultFd.write(errormsg)
                continue
            
            sn = attrs["sn"]
            givenName = attrs["givenName"]
            password = attrs["password"]
	    if password_hash == "SHA-1":
		hashPassword = binascii.b2a_hex(sha.new(password).digest())
	    elif password_hash is None:
		hashPassword = password
		
            if attrs.has_key("GooglePop"):
                pop = isYes(attrs["GooglePop"])
            if attrs.has_key("GoogleImap"):
                imap = isYes(attrs["GoogleImap"])

            # Check ignore user or not
            if gDomain.isIgnoreUsers(username):
                continue

            # Add user to Google Apps
            try:
                service.CreateUser(username, sn, givenName, hashPassword, password_hash_function=password_hash)
                emailsettings.UpdatePop(username,pop,gdata.apps.emailsettings.service.ALL_MAIL,gdata.apps.emailsettings.service.KEEP)
                emailsettings.UpdateImap(username,imap)
            except gdata.apps.service.AppsForYourDomainException, e:
                errormsg = username + "," + gDomain.errorstr(e) + "\n"
                sys.stderr.write(errormsg)
                resultFd.write(errormsg)
                error = error + 1
            except Exception , e:
                errormsg = username + "," + '"' + str(e) + '"' + "\n"
                sys.stderr.write(errormsg)
                resultFd.write(errormsg)
                error = error + 1
            else:
                msg = username + ",OK\n"
                sys.stdout.write(msg)
                resultFd.write(msg)
                success = success + 1

        resultFd.flush()
        r = r + 1  # Increment row counter
                 

    # Create summary 
    msg = str((r-1)) + " user entries are handled.\n"
    summaryFd.write(msg)
    msg = "Success to add:" + str(success) + " user entries\n"
    summaryFd.write(msg)
    msg = "Fail to add:" + str(error) + " user entries\n"
    summaryFd.write(msg)

    resultFd.close()
    summaryFd.close()
    sys.exit(0)

main()
