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

# googleapps-account-csvusermod.py 
# - Account modification on 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-11-25, 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 = "usermod"
    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 = None
        imap = None
        sn = ""
        givenName = ""
        password = ""
        hashPassword = None
        if len(row) == 0:
            continue

        if r == 0:
            # Create header list
            for key in row:
                header.append(key)
        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 ignore user or not
            if gDomain.isIgnoreUsers(username):
                continue

            # Check sn or givenName or password is included in attrs.
            if attrs.has_key("sn"):
                sn = attrs["sn"]
            if attrs.has_key("givenName"):
                givenName = attrs["givenName"]
            if attrs.has_key("password"):
                password = attrs["password"]
                if len(password) > 0:
                    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"])

            # Add user to Google Apps
            try:
                if (attrs.has_key("sn") or attrs.has_key("givenName") or attrs.has_key("password")):
                    userEntry = service.RetrieveUser(username)
                    orig_sn = userEntry.name.family_name
                    orig_givenName = userEntry.name.given_name
                    if hashPassword:
                        userEntry.login =  gdata.apps.Login(user_name=username, password=hashPassword, hash_function_name=password_hash)
                    if len(sn) == 0:
                        sn = orig_sn
                    if len(givenName) == 0:
                        givenName = orig_givenName
                    userEntry.name = gdata.apps.Name(family_name=sn, given_name=givenName)
                    service.UpdateUser(username, userEntry)
                if pop != None:
                    emailsettings.UpdatePop(username,pop,gdata.apps.emailsettings.service.ALL_MAIL,gdata.apps.emailsettings.service.KEEP)
                if imap != None:
                    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 modify:" + str(success) + " user entries\n"
    summaryFd.write(msg)
    msg = "Fail to modify:" + str(error) + " user entries\n"
    summaryFd.write(msg)

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

main()
