#!/usr/bin/python

import os
import sys
import subprocess
import time
import signal
import socket
import struct
import fcntl
import tempfile

def get_config(name):
    return os.environ.get(name)

def get_config_bool(name):
    val = os.environ.get(name)
    return (val and val.lower() == 'true')

def get_ip(ifname):
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    return socket.inet_ntoa(fcntl.ioctl(
        s.fileno(),
        0x8915,  # SIOCGIFADDR
        struct.pack('256s', ifname[:15])
    )[20:24])

class LDM:
    def __init__(self, vt, display):
        self.vt = vt
        self.display = display
        self.server = get_config('SERVER')
        self.use_xfs = get_config_bool('USE_XFS')
        self.remotecmd = get_config('LDM_REMOTECMD') or '/etc/X11/Xsession'
        self.use_sound = get_config_bool('SOUND')
        if self.use_sound:
            self.ip = get_ip('eth0')
            self.sound_daemon = get_config('SOUND_DAEMON') or 'esd'

        if self.use_xfs:
            xfs_server = get_config('XFS_SERVER') or self.server
            self.fontpath = "tcp/%s:7100" % xfs_server

        # Save xauth info some writable tmpfs file.
        self.authfile = tempfile.mktemp()

    def run(self):
        null = open('/dev/null', 'w')
        logfile = open('/var/log/ldm.log', 'a')
        
        os.dup2(null.fileno(), sys.stdin.fileno())
        os.dup2(logfile.fileno(), sys.stdout.fileno())
        os.dup2(logfile.fileno(), sys.stderr.fileno())

        while True:
            server_opts = ['-br', '-ac', '-noreset']
            
            if self.use_xfs:
                server_opts += ['-fp', self.fontpath]

            server_command = ['X', '-auth', self.authfile] + server_opts + [self.vt, self.display]
            server = subprocess.Popen(server_command, stdout=sys.stdout, stderr=sys.stderr)
            
            env = os.environ.copy()
            env['DISPLAY'] = self.display
            env['XAUTHORITY'] = self.authfile
            
            time.sleep(5)

            # Generate an X authority key in ~/.Xauthority
            xauth_command = ['xauth', '-f', self.authfile, 'generate', self.display]
            xauth = subprocess.Popen(xauth_command, stdout=sys.stdout, stderr=sys.stderr, env=env)
            os.waitpid(xauth.pid, 0)

            greeter = subprocess.Popen(['/usr/lib/ltsp/greeters/gtk'],
                                       stdout=subprocess.PIPE, stderr=sys.stderr, env=env)
            greeter_output = greeter.stdout.readlines()
            if len(greeter_output) == 2:
                username = greeter_output[0][:-1]
                password = greeter_output[1][:-1]

                self.spawn_session(username, password, self.remotecmd)
            else:
                print "Didn't get the right output from the greeter"

            os.kill(server.pid, signal.SIGTERM)
            os.waitpid(server.pid, 0)

    def spawn_session(self, username, password, session_manager):
        pipe_read, pipe_write = os.pipe()
        pid = os.fork()

        if pid == 0:
            os.close(pipe_write)
            sys.stdin.close()
            os.setsid()
            os.environ['DISPLAY'] = self.display
            os.environ['XAUTHORITY'] = self.authfile
            os.environ['LDM_ASKPASS_FD'] = str(pipe_read)
            os.environ['SSH_ASKPASS'] = '/usr/lib/ltsp/ldm-askpass'

            ssh_opts = ['-v',
                       '-X',
                        '-c', 'blowfish-cbc,aes128-cbc,3des-cbc']

            ssh_auth = ['%s@%s' % (username,self.server)]

            if self.use_sound:
                if self.sound_daemon == 'esd':
                    print "info: Enabling esd sound support."
                    # Could start using esddsp, but it is not enabled
		    # because it gave problems when using firefox.
                    #   esddsp', '-m','--server=%s:16001' % (self.ip)
                    espeakerport = 16001
                    sound_cmd = ['ESPEAKER=%s:%d' % (self.ip, espeakerport)]
                elif self.sound_daemon == 'nasd':
                    print "info: Enabling nasd sound support."
                    # Could use the audiooss package to set LD_PRELOAD.
                    # Not enabled by default to avoid problems with
                    # firefox.
                    sound_cmd = ['AUDIOSERVER=%s:0' % (self.ip)]
                else:
                    print "error: Unsupported sound daemon: '%s'" % \
                          (self.sound_daemon)
                    sound_cmd = []
            else:
                print "info: Not enabling sound support."
                sound_cmd = []

            ssh_remote_command = ['env',
                                  'LTSP_CLIENT="%s"' % (socket.gethostname()),
                                  ] + sound_cmd + [
                                  session_manager,
                                  ';',
                                  'kill -1 $PPID']

            if 'NETWORK_COMPRESSION' in os.environ:
                ssh_opts.append('-C')
            
            command = ['ssh'] + ssh_opts + ssh_auth + ssh_remote_command
            print "ssh command line:", command
            sys.stdout.flush()

            os.execvp('ssh', command)
            sys.exit(1)

        os.close(pipe_read)
        os.write(pipe_write,password)
        os.close(pipe_write)
        os.waitpid(pid, 0)

if len(sys.argv) < 3:
    sys.stderr.write('Usage: ldm <vt[1-N]> <:[0-N]>\n')
    sys.exit(1)

vt, display = sys.argv[1:]
ldm = LDM(vt, display)
ldm.run()
