########################################################################
# $Header: /var/local/cvsroot/4Suite/Ft/Server/Client/__init__.py,v 1.9 2005/03/22 09:58:58 mbrown Exp $
"""
Repository client (4ss, 4ss_manager) base module

Copyright 2005 Fourthought, Inc. (USA).
Detailed license and copyright information: http://4suite.org/COPYRIGHT
Project home, documentation, distributions: http://4suite.org/
"""

import os

from Ft.Server import FtServerBaseException
from Ft.Server.Common import ClAuthenticate
from Ft.Server.Client import Core

import MessageSource


Error = MessageSource.Error

class FtServerClientException(FtServerBaseException):
    """
    Exception class for errors incurred while using the
    repository clients (4ss, 4ss_manager).
    """
    MessageSource = MessageSource


def GetAuthentication(options=None):
    """
    Returns authentication arguments for connecting to a repository.

    Get Authentication information for a Client connection to the repository
    1: look in the options dictionary for "anonymous"
    2: look in the options dictionary for "username"
    3: look in the options dictionary for "port"
    4: look in the options dictionary for "host"
    5:  If there is no username, then look for the FTSS_AGENT env var to get information
    6: If there still is no username, then look for FTSS_USERNAME env var
    7: If there still is no user name then prompt for it.
    8: look in the options dictionary for "password"
    9: look in the options dictionary for "passwdhash"
    10: If there is no password, then ask the password manager (from 4ss login)
    11: If there still is no password then prompt for it.
    12: If there is no host, then prompt for it
    13: If there is no port then prompt for it
    """
    options = options or {}
    hasUserName = hasPasswd = False
    userName = None
    passwdHash = None

    # Is this an anonymous login? (ignores other username choices)
    if options.has_key('anonymous'):
        hasUserName = True
        hasPasswd = True
    else:
        if options.has_key('username'):
            hasUserName = True
            userName = options['username']
        if options.has_key('password'):
            hasPasswd = True
            passwdHash = ClAuthenticate.HashPasswd(options['password'])
        if options.has_key('passwdhash'):
            hasPasswd = True
            passwdHash = options['passwdhash']

    host = options.get('host')
    port = int(options.get('port', 0))

    # See if there is an agent (set and non-empty)
    if not hasUserName and os.environ.get('FTSS_AGENT'):
        userName, passwdHash, h, po = eval(os.environ['FTSS_AGENT'])
        hasUserName = hasPasswd = True
        if not host:
            host = h
        if not port:
            port = int(po)

    # See if 'logged in' (set and non-empty)
    if not hasUserName and os.environ.get('FTSS_USERNAME'):
        userName = os.environ['FTSS_USERNAME']
        hasUserName = True

    #All else failed: prompt user
    if not hasUserName:
        userName = ClAuthenticate.GetUserName('4SS user name: ', emptyOK=False)

    if not hasPasswd:
        pm = ClAuthenticate.PasswordFileManager()
        pa, h, p = pm.getUserEntry(userName)
        if pa:
            passwdHash = pa
            hasPasswd = True
        if not host and h:
            host = h
        if not port and p:
            port = int(p)

    if not hasPasswd:
        passwd = ClAuthenticate.GetPass("Password for %s: " % userName)
        passwdHash = ClAuthenticate.HashPasswd(passwd)

    if not host:
        host = ClAuthenticate.GetHostName('Host <%s>: ' % Core.FTRPC_HOST)
        host = host or Core.FTRPC_HOST

    if not port:
        port = ClAuthenticate.GetPort('Port <%i>: ' % Core.FTRPC_PORT)
        try:
            port = int(port or Core.FTRPC_PORT)
        except ValueError:
            raise ValueError('Invalid port %r' % port)

    return (userName, passwdHash, host, port)


def SmartLogin(options=None):
    """
    Returns a new repository connection.
    """
    userName, passwdHash, host, port = GetAuthentication(options)
    return Core.GetRepository(userName, passwdHash, host, port)

