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

# googleapps-account-passwd: Password change for Google Apps
# Copyright (C) TAKEDA Yasuma @ Open Source Solution Technology Co. Ltd.
#
# License: GNU General Public License version 2 or later
# Date: 2010-09-22, since 2008-08-22

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

# from Google
import gdata.apps.service

# from OSSTech
import googleappsutils.domain

def usage():
    sys.stderr.write("Usage: " + sys.argv[0] + " [-s|-c] <username@domain>\n")
    sys.stderr.write("   -s: read password from stdin\n")
    sys.stderr.write("   -c: read password from console\n")
    sys.exit(1)

def main():
    domain = None
    password_hash = None
    
    try:
        (opts, args) = getopt.getopt(sys.argv[1:], "d:sc")
    except getopt.GetoptError:
        sys.stderr.write("Error : Invalid Option\n")
        usage()
    
    readstdin = False
    readconsole = False
    for (opt, value) in opts:
        if opt == "-s":
            readstdin = True
        if opt == "-c":
            readconsole = True

    try:
        mailaddr = args[0]
        m = string.split(mailaddr,'@')
        username = m[0]
        domain = m[1]
    except IndexError:
        sys.stderr.write("Error : mail address is needed.\n")
        usage()
    if len(domain) == 0:
        usage()

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

    # Password Hash Type
    password_hash = gDomain.getPasswordHash()

    # No Error
    error = 0

    # Read password
    if readconsole:
	newpassword = getpass.getpass("")
	newpassword2 = getpass.getpass("")
	if len(newpassword ) < 6:
            sys.stderr.write("BAD PASSWORD: password is too short.\n")
            sys.exit(1)
	elif (newpassword != newpassword2):
            sys.stderr.write("BAD PASSWORD: password is mismatch.\n")
            sys.exit(1)
    elif readstdin:
	newpassword = sys.stdin.readline()
	newpassword2 = sys.stdin.readline()
	if len(newpassword ) < 6:
            sys.stderr.write("BAD PASSWORD: password is too short.\n")
            sys.exit(1)
	elif (newpassword != newpassword2):
            sys.stderr.write("BAD PASSWORD: password is mismatch.\n")
            sys.exit(1)
    else:
        sys.stdout.write("Changing password for " + username + "\n")
        while(1):
            newpassword = getpass.getpass("(New) password: ")
            newpassword2 = getpass.getpass("Retype (New) password: ")
            if len(newpassword ) < 6:
                sys.stderr.write("BAD PASSWORD: password is too short.\n")
                continue
            elif (newpassword != newpassword2):
                sys.stderr.write("BAD PASSWORD: password is mismatch.\n")
                continue
            else:
                break

    # Changing Password
    try:
        service = gdata.apps.service.AppsService(gDomain.admin,gDomain.adminPass,gDomain.domain)
        service.ProgrammaticLogin()
    except gdata.apps.service.AppsForYourDomainException , e:
        sys.stderr.write("Error : Can't connect to Google Apps Domain by Administrator\n")
        sys.stderr.write(gDomain.errorstr(e))
        sys.exit(1)
    except Exception, e:
        sys.stderr.write("Error : Can't connect to Google Apps Domain with unexpected error.\n")
        sys.stderr.write(str(e))
        sys.exit(1)

    retry = 0
    MAX_RETRY=10
    while retry < MAX_RETRY:
        try:
            userEntry = service.RetrieveUser(username)
            if password_hash == "SHA-1":
                hashPassword = binascii.b2a_hex(sha.new(string.strip(newpassword)).digest())
            elif password_hash is None:
                hashPassword = string.strip(newpassword)
            userEntry.login =  gdata.apps.Login(user_name=username, password=hashPassword, hash_function_name=password_hash)
            service.UpdateUser(username, userEntry)
            break
        except gdata.apps.service.AppsForYourDomainException, e:
            if e.error_code == 1000:
                retry += 1
                continue
            elif e.error_code == 1301:
                sys.stderr.write("Failed to change password(No such user).\n")
            else:
                sys.stderr.write("Failed to change password.\n")
            sys.exit(1)
        except:
            sys.stderr.write("Failed to change password.\n")
            sys.exit(1)

    if retry == MAX_RETRY:
        sys.stderr.write("Failed to change password by unknown reason.\n")
        sys.exit(1)
    elif not readconsole and not readstdin:
        sys.stdout.write("Password is changed.\n")

    sys.exit(0)

main()
