#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2008 Asher256 
#
# Contact : contact@asher256.com
# Website : http://blog.asher256.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 St, Fifth Floor, Boston, MA  02110-1301  USA
#
"""Send xauth key to different users.

"""

import sys
import os
import re
import pwd
from getopt import gnu_getopt, GetoptError

VERSION = '0.1'

SOURCE_USER = ''
DESTINATION_USER = ''
DISPLAY = ':0.0'
VERBOSE = False
DEV_NULL = ' >/dev/null 2>&1'

def vprint(string):
    """Print 'string' if --verbose is defined.
    
    """
    if VERBOSE != False:
        print string

def check_environment():
    """Check if all required environment variables are available.

    """
    display = os.getenv('DISPLAY')
    if display == None:
        print 'DISPLAY environment variable is not declared.'
        sys.exit(1)
    else:
        globals()["DISPLAY"] = display 

def user_exists(user):
    """Return True if the user exists.
    
    """
    try:
        pwd.getpwnam(user)
    except KeyError:
        return False
    else:
        return True

def handle_arguments():
    """Handle options in the arguments (argv).

    """
    try:
        args = sys.argv[1:]
        optlist = gnu_getopt(args, 'vh', ['help', 'verbose'])
    except GetoptError:
        print 'Error when parsing arguments.'
        print "--help for more informations."
        sys.exit(1)

    if len(sys.argv) < 2:
        print 'What\'s the destination user ?'
        print "--help for more informations."
        sys.exit(1)

    for user in optlist[1]:
        if not user_exists(user):
            print "The user '%s' doesn't exists." % user
            sys.exit(1)
        else:
            globals()["DESTINATION_USER"] = user

        break

    for option, value in optlist[0]:
        print option
        if option in ['-v', '--verbose']:
            globals()['VERBOSE'] = True
            globals()['DEV_NULL'] = ''
        elif option in ['-h', '--help']:
            print __doc__[0:-2]
            print
            print 'Usage: %s [OPTIONS] destination_user <source_user>' \
                  % os.path.basename(sys.argv[0])
            print
            print "OPTIONS :"
            print "          -h, --help            Show this help"
            print "          -v, --verbose         Verbose mode"
            print
            sys.exit(0)

def commands_required(*cmd_list):
    """This function tests if all programs in 
    the arguments are available in the environment
    variable 'PATH'.

    """
    path = os.getenv('PATH')
    if path != None:
        path_list = path.split(os.pathsep)
    else:
        print "The environment variable PATH is not defined."
        sys.exit(1)

    for command in cmd_list:
        error = True
        for path in path_list:
            command_path = os.path.join(path, command)
            if os.access(command_path, os.X_OK):
                error = False
                break

        if error:
            print 'The command \'%s\' is not found.' % command
            sys.exit(1)

def su_command_generator(command, user=''):
    """Convert a command to : su -c 'command' user and return that.

    """
    command = re.sub(r"(['\\])", r"\\\1", command)
    command = 'su -c \'' + command + '\''
    if user != '':
        command += ' ' + user
    return command

def send_xauth(destination_user, source_user=''):
    """Send the authentication to the destination user

    If source_user is '', the source user is the actual user (automatically
    detected).
    
    """
    if source_user != '':
        sys.stdout.write(source_user + '\'s ')
    print 'xauth key will be sent to', destination_user + '...'
    print

    auth_tmpfile = '/tmp/sendxauth' + str(os.getpid())

    try:
        # extract
        command = 'xauth extract ' + auth_tmpfile + ' ' + DISPLAY 
        if source_user != '':
            sys.stdout.write('You must enter ' + source_user + ' password : ')
            command = su_command_generator(command)

        vprint(command)
        result = os.system(command + DEV_NULL)
        if source_user != '':
            print
        if result != 0:
            print 'Errors when extracting xauth key.'
            sys.exit(1)

        # chmod auth key
        os.chmod(auth_tmpfile, 0777)

        #Â merge
        sys.stderr.write('You must enter ' + destination_user + ' password : ')
        destination_home = pwd.getpwnam(destination_user)[5]
        authfile = os.path.join(destination_home, '.Xauthority')

        # masquer les ' et \ dans authfile
        command = su_command_generator('xauth merge ' + auth_tmpfile,
                     destination_user)
        command = 'XAUTHORITY=\'' + authfile + '\' '  + command
        vprint(command)
        result = os.system(command + DEV_NULL)
        if DEV_NULL != '':
            print

        if result != 0:
            print 'Error when merging xauth key by ' + destination_user + '.'
            sys.exit(1)
        else:
            print "xauthority is sent to %s !" % destination_user
            print 
            print "You maybe must declare these shell variables before " + \
                  "running a graphical program :"
            print "export DISPLAY=\"%s\"" % DISPLAY
            print "export XAUTHORITY=\"%s/.Xauthority\"" % \
                  pwd.getpwnam(destination_user)[5]
    finally:
        try:
            os.remove(auth_tmpfile)
        except OSError:
            print 'Warning: Cannot remove ' + auth_tmpfile + '...'
        else:
            vprint('Notice: ' + auth_tmpfile + ' deleted ;)')

if __name__ == '__main__':
    try:
        commands_required('xauth', 'su')
        check_environment()
        handle_arguments()
        send_xauth(DESTINATION_USER, SOURCE_USER)
    except KeyboardInterrupt:
        print "Interrupted."

# vim:ai:et:sw=4:ts=4:sts=4:tw=78:fenc=utf-8

