#!/usr/bin/python -u
#
# Command line wrapper for Update Agent
# Copyright (c) 1999-2001 Red Hat, Inc.  Distributed under GPL.
#
# Author: Preston Brown <pbrown@redhat.com>

import sys, os
import rpm
import string
from types import StringType
sys.path.append("/usr/share/rhn/")
from up2date_client import config
from up2date_client import up2dateLog
from up2date_client import up2dateMessages
from up2date_client import up2dateErrors
from up2date_client import rpcServer
from up2date_client import up2dateAuth
from up2date_client import rhnPackageInfo
from up2date_client import rhnChannel
from up2date_client import packageList
from up2date_client import up2dateBatch
from up2date_client import gpgUtils
from up2date_client import rhnHardware
from up2date_client import rpmUtils
from up2date_client import depSolver

from up2date_client.translate import _, N_, cat

cfg = config.initUp2dateConfig()
# not real fond of this, need to figure out a better
# way to test if we can write to the log file.
try:
    log = up2dateLog.initLog()
except IOError, e:
    print up2dateMessages.rootWarningMsg
    sys.exit(1)

from up2date_client import wrapperUtils
from up2date_client import up2date

try:
    import clap
except ImportError:
    from up2date_client import clap

try:
    from rhn import rpclib
except ImportError:
    rpclib = __import__("xmlrpclib")
    
try:
    from up2date_client import lilocfg
except ImportError:
    lilocfg = None

# we want to be somewhat less verbose if were not on a tty...
global isatty
isatty = None

optionsTable = [
        [None,  "configure",    None, 
            _("configure Update Agent options")],
        ['d',   "download",     None,
            _("download packages only, even if configuration says to install")],
        [None,  "src",          None,
            _("Download src packages as well as binary rpms")],
        [None,  "nosrc",        None,
            _("Do not download src packages (overrides config setting if set)")],
        [None,  "dbpath",       StringType,
            _("Specify a path where an alternate rpm db is found"), "<dir>"],
        ['f',   "force",        None,
            _("Force package installation, overriding package and file skip list")],
        ['i',   "install",      None,
            _("install packages, even if configuration says to download only")],
        [None, "justdb",        None,
            _("Only add packages to database, do not install to the filesystem")],
        ['l',   "list",         None,
            _("list packages available for retrieval")],
	[None,  "dry-run",	None,
	    _("Do everything but download and install packages")],
        ['h',   "help",         None,
            _("this help screen")],
        ['?',   "usage",        None,
            _("Briefly describe the options")],
        ['k',   "packagedir",   StringType,
            _("colon separated path of directories to look in for packages")],
        [None,  "nosig",        None,
            _("do not use GPG to check package signatures")],
        [None,  "nox",          None,
            _("do not attempt to use X")],
        ['p',   "packages",     None,
            _("update packages associated with this System Profile on Red Hat Network")],
        [None, "hardware",      None,
            _("up2date hardware profile associated with this System Profile on Red Hat Network")],
        [None,  "showall",      None,
            _("List all packages available for download")],
        [None,  "solvedeps",    StringType,
            _("finds, downloads, and installs the packages needed to solve the list of deps"), "<deps>"],
        [None,  "tmpdir",       StringType,
            _("where to store temporary files / RPMs"), "<directory>"],
        ['u',   "update",       None,
            _("update system with all relevant packages")],
        [None,  "version",      None,
            _("show program version information")],
        ['v',   "verbose",      [],
            _("Show additional output")],
        [None,  "show-channels",None,
            _("Show the channel names along with the package name where approriate")],
        [None,  "whatprovides", StringType,
            _("shows the packages which solve the comma separated list of deps"), "<deps>"],
        [None, "channel", StringType,
            _("Specify which channels to use by channel label")],
	[None, "gpg-flags", None,
	       _("Show the flags that gpg will be invoked with (the keyring, etc)")],
        [None, "nodownload",    None,
            _("Do not download packages at all. For testing purposes")]
    ]            
    
def printHelp(poptContext, stream = sys.stdout):
    poptContext.printHelp(stream)
    stream.write("\n" + _("""\
When operating in command line mode, specifying package names as arguments to
the program will attempt to retrieve (and possibly install, based on your
configuration) those packages.  Version, release, and architecture details will
be determined by the Update Agent automatically.""") + "\n")

def printUsage(poptContext, stream = sys.stdout):
    poptContext.printUsage(stream)

def gpgWarning2(hasGui):
    def cb(arg):
        return arg

    errMsg = up2dateMessages.gpgWarning2Msg % rpmUtils.getGPGflags()
 
    if hasGui:
        try:
            from up2date_client import gui 
	    import gnome, gnome.ui
            dlg = gnome.ui.GnomeQuestionDialog(errMsg+_("\n\nInstall key?"),
                                               cb)
            if not dlg.run_and_close():
                if gpgUtils.addGPGKey():
                    dlg = gnome.ui.GnomeErrorDialog(_("Some sort of error occurred adding the Red Hat\nGPG key to your keyring."))
                    dlg.run_and_close()
                    return 1
                else:
                    return 0
                
            return 1
        except (ImportError, RuntimeError) :
            print _("Unable to open gui. Try `up2date --nox`")
            print errMsg
            print
            return 1
    else:
        print errMsg
        print
        return 1

def sslWarning(hasGui):
    def cb(arg):
        return arg

    errMsg = _("""Your system libraries do not support SSL (secure) connections.  Any data
that you send or receive from redhat.com will be transmitted in the clear.

""")

    if hasGui:
        try:
            from up2date_client import gui
	    import  gnome, gnome.ui
            dlg = gnome.ui.GnomeQuestionDialog(errMsg + _("Continue anyway?"),
                                               cb)
            if dlg.run_and_close():
                return 1
            else:
                return 0
        except:
            print _("Unable to open gui. Try `up2date --nox`")
            print errMsg
            return 1
    else:
        print errMsg
        return 1

def sanityChecks(fromDaemon, hasGui,argObj):
    if up2dateAuth.getSystemId() == None:
        # FIXME
        # fire up rhn_register at this point...
        wrapperUtils.warningDialog(up2dateMessages.registeredWarningMsg, hasGui)
        if not fromDaemon:
            sys.exit(1)
        return 1
    
    #  see if /var/spool/up2date exists
    if up2date.checkForStorageDir():
        wrapperUtils.warningDialog(up2dateMessages.storageDirWarningMsg,hasGui)
        if not fromDaemon:
            sys.exit(1)
        return 1

    if cfg.readEntry("useGPG") and gpgUtils.checkGPGInstallation() == 1:
        wrapperUtils.warningDialog(up2dateMessages.gpgWarning1Msg, hasGui)
        if not fromDaemon:
            sys.exit(1)
        return 1

    if cfg.readEntry("useGPG") and gpgUtils.checkGPGInstallation() == 2:
        if gpgWarning2(hasGui):
            if not fromDaemon:
                sys.exit(1)
        return 1

    if not rpcServer.hasSSL():
        if sslWarning(hasGui):
            if not fromDaemon:
                sys.exit(1)
        return 1

def showInfoMessages(fromDaemon,hasGui, argObj):
    if argObj.getLong("help"):
        printHelp(argObj.ctx)
        if not fromDaemon:
            sys.exit(0)
        return 1

    if argObj.getLong("usage"):
        printUsage(argObj.ctx)
        if not fromDaemon:
            sys.exit(0)
        return 1

    if argObj.getLong("version"):
	showVersion(hasGui)
        if not fromDaemon:
            sys.exit(0)
        return 1

def checkForRhnNetworkConfigs(hasGui):
    """This function checks to see if we've setup any network options for
    rhn_register. If so, and were havent configured those the same for up2date,
    clone the ones from rhn_register"""
    cfg = config.initUp2dateConfig()

    
    # read the rhn_register too
    regCfg = config.RegisterPeekConfig()
    regCfg.load()
    
    # read the config, if NetworkSetup isnt set, the user is running
    # it the first time. After they go though the config, set enableProxy 
    if cfg.hasEntry('networkSetup'):
        return

    # the info isnt in rhn_register config either, skip
    if not regCfg.hasEntry('networkSetup'):
        return

    # look and see if the config is non-default
    # if so, skip it. We dont want to clobber modified configs
    # but for the first run on a default system, these should all be default
    if cfg.readEntry("enableProxy") == 1:
        return 
    if cfg.readEntry("httpProxy") != "":
        return
    if cfg.readEntry("proxyUser") != "":
        return
    if cfg.readEntry("proxyPassword") != "":
        return
    if cfg.readEntry("enableProxyAuth") == 1:
        return


    # looks like were clear to migrate the settings
    print "Migrating network settings from rhn_register"
    log.log_me("Migrating network settings from rhn_register")
    cfg.writeEntry("enableProxy", regCfg.readEntry("enableProxy"))
    if regCfg.readEntry("httpProxy"):
    	cfg.writeEntry("httpProxy", regCfg.readEntry("httpProxy"))
    if regCfg.readEntry("proxyUser"):
    	cfg.writeEntry("proxyUser", regCfg.readEntry("proxyUser"))
    if  regCfg.readEntry("proxyPassword"):
    	cfg.writeEntry("proxyPassword", regCfg.readEntry("proxyPassword"))
    cfg.writeEntry("enableProxyAuth", regCfg.readEntry("enableProxyAuth"))
    cfg.writeEntry("serverURL",  regCfg.readEntry("serverURL"))
    if regCfg.readEntry("noSSLServerURL"):
    	cfg.writeEntry("noSSLServerURL",  regCfg.readEntry("noSSLServerURL"))
    if regCfg.readEntry("sslCaCert"):
    	cfg.writeEntry("sslCACert", regCfg.readEntry("sslCACert"))
    if regCfg.readEntry("useNoSSLForPackages"):
    	cfg.writeEntry("useNoSSLForPackages", regCfg.readEntry("useNoSSLForPackages"))
    cfg.writeEntry("networkSetup", 1)
    cfg.save()
    # FIXME
#    up2date.reloadConfig()
        
def main(arglist = sys.argv, fromDaemon = 0):
    hasGui = 0
    nox = 0
    nogui = 0
    configure = 0
    dry_run = 0

    # see what we got called as 
    if os.path.basename(sys.argv[0]) == "up2date-nox":
	nox = 1

    if os.path.basename(sys.argv[0]) == "up2date-config":
        configure = 1
        
    # clap on
    argObj = clap.Clap(optionsTable, "[OPTIONS] <packages>", aliasing = 1)
    try:
        argObj.process(arglist)
    except clap.ClapError, e:
        # clap off
        ReportError("Error parsing command line arguments: %s" % 
            string.join(map(str, e.args)))
        if fromDaemon:
            return 1
        sys.exit(1)
        # the clapper
    
    pkgNames = argObj.args

    nox = nox or argObj.getLong("nox")
    
    # detect if were running on a tty or not
    global isatty
    if sys.stdout.isatty():
	    isatty = 1
    else:
	    isatty = None

    try:
        if os.access("/usr/share/rhn/up2date_client/gui.py", os.R_OK):
            if os.environ["DISPLAY"] != "":
		if not nox:
                	hasGui = 1
    except:        
        pass


    showInfoMessages(fromDaemon, hasGui, argObj)
    
    # set a default warning message callback, the gui version
    # should reset this
    wrapperUtils.warningCallback = wrapperUtils.printit


    # figure out if were entering a differnt "mode" or if we
    # want to open the gui app
    refreshmodes = ["packages", "hardware"]
    refreshmode = None
    for mode in refreshmodes:
        if argObj.getLong(mode):
            refreshmode = 1
            continue

    # if any of the non gui mode options are specified, set guimode to None
    modes = ["showall", "update", "list", "dry-run", "show-channels",
             "whatprovides","solvedeps", "configure"]
    guimode = 1
    for mode in modes:
        if argObj.getLong(mode):
            guimode = None
            continue
        
    if len(pkgNames):
        guimode = None


    tempchannels = []
    depslist = []
    verbosecount = 0
    depslist = argObj.getLong("whatprovides")
    if depslist:
        cfg.writeEntry("depslist", depslist)
    else:
        depslist = []
    for i in argObj.getLong("verbose"):
	verbosecount = verbosecount + 1
	if verbosecount >= 2:
	    try:
	    	rpm.setVerbosity(rpm.RPMLOG_DEBUG) 
	    except AttributeError:
		print "extra verbosity not supported in this version of rpm"
    if argObj.getLong("download"):
        cfg.writeEntry("retrieveOnly", 1)
    if argObj.getLong("nodownload"):
        cfg.writeEntry("noDownload", 1)
    if argObj.getLong("install"):
        cfg.writeEntry("retrieveOnly", 0)
    if argObj.getLong("force"):
        cfg.writeEntry("forceInstall", 1)
    if argObj.getLong("verbose"):
        cfg.writeEntry("verbose", 1)
    if argObj.getLong("src"):
        cfg.writeEntry("retrieveSource", 1)
    if argObj.getLong("nosrc"):
        cfg.writeEntry("retrieveSource", 0)
    if argObj.getLong("channel"):
	tempchannels.append(argObj.getLong("channel"))
    tmpdir = argObj.getLong("tmpdir")
    if tmpdir:
        cfg.writeEntry("storageDir", tmpdir)
    packagedir = argObj.getLong("packagedir")
    if packagedir is not None:
        packagedir = os.path.abspath(os.path.expanduser(packagedir))
        cfg.writeEntry("packageDir", packagedir)
    if argObj.getLong("nosig"):
        cfg.writeEntry("useGPG", 0)
    if argObj.getLong("dbpath") is not None:
        cfg.writeEntry("dbpath", argObj.getLong("dbpath"))
    if argObj.getLong("justdb"):
        cfg.writeEntry("justdb", 1)
    if argObj.getLong("show-channels"):
        cfg.writeEntry("showChannels", 1)
    if argObj.getLong("dry-run"):
	dry_run = 1
    if argObj.getLong("gpg-flags"):
	print rpmUtils.getGPGflags()
	return 0

    if len(tempchannels):
        try:
            up2dateAuth.updateLoginInfo()
        except rpclib.Fault, f:
            faultError(hasGui,f.faultString)
            sys.exit(1)
        except up2dateErrors.CommunicationError, e: 
            print e 
            sys.exit(1) 
        rhnChannel.updateChannels(tempchannels)


    # packages and hardare arent in the mode list,
    # since they would al
    if refreshmode:
        if argObj.getLong("packages"):
            try:
                up2dateAuth.updateLoginInfo()
            except rpclib.Fault, f:
                faultError(hasGui,f.faultString)
                sys.exit(1)
            except up2dateErrors.CommunicationError, e: 
                print e 
                sys.exit(1) 

            print _("Updating package profile...")
            rhnPackageInfo.updatePackageProfile()
            # if we just specify `up2date -p` exit, but
            # keep going otherwise. This means , up2date

        if argObj.getLong("hardware"):
            try:
                up2dateAuth.updateLoginInfo()
            except rpclib.Fault, f:
                faultError(hasGui,f.faultString)
                sys.exit(1)
            except up2dateErrors.CommunicationError, e: 
                print e 
                sys.exit(1) 
            print _("Updating hardware profile...")
            rhnHardware.updateHardware()

        # if we didnt get any other mode arguments, exit
        # if we did, keep chugging and run those as well
        if guimode:
            return 0
    if argObj.getLong("showall"):
        # FIXME: hack, should set a variable here and then run it later
        try:
            up2dateAuth.updateLoginInfo()
        except rpclib.Fault, f:
            faultError(hasGui,f.faultString)
            sys.exit(1)
        except up2dateErrors.CommunicationError, e: 
            print e 
            sys.exit(1) 
        printList(up2date.getAvailablePackageList())
        return 0


    fullUpdate = argObj.getLong("update")
    configure = configure or argObj.getLong("configure")

    # show any useage/help/info/version info
    ret = showInfoMessages(fromDaemon, hasGui, argObj)
    if ret:
        return ret

    # see if were running as root, before running configure
    if os.geteuid() != 0:
        wrapperUtils.warningDialog(up2dateMessages.rootWarningMsg, hasGui)
        if not fromDaemon:
            sys.exit(1)

    # see if rhn_register has configured a proxy, if so, use it's values
    checkForRhnNetworkConfigs(hasGui)
    
    if configure:
        if hasGui:
            try:
                from up2date_client import configdlg
            except:
                hasGui = 0
            if hasGui:
                configdlg.main()
                if fromDaemon:
                    return 0
                else:
                    sys.exit(0)
        if not hasGui:
            from up2date_client import text_config
            text_config.main()
            if fromDaemon:
                return 1
            else:
                sys.exit(1)

    # run all the sanity checks (gpg key, paths, etc)
    ret = sanityChecks(fromDaemon, hasGui, argObj)
    if ret:
        return ret

    # initilized the package sources
    if not up2dateAuth.loginInfo:
        try:
            up2dateAuth.updateLoginInfo()
        except rpclib.Fault, f:
            faultError(hasGui,f.faultString)
            sys.exit(1)

        except up2dateErrors.CommunicationError, e: 
            print e
            sys.exit(1) 

#FIXME

    if len(depslist):
       return whatprovides(depslist)

    if argObj.getLong("solvedeps"):
        # maybe this will handle comboa cases of packages and deps specified?? NEEDSTEST
        extraPackages = whatprovides(argObj.getLong("solvedeps"), 1)
        if extraPackages:
            pkgNames = pkgNames + extraPackages
        else:
            print _("No packages were found that satisfy those dependencies.")
            sys.exit(1)

    if cfg.readEntry("showChannels"):
        channels = up2dateAuth.loginInfo['X-RHN-Auth-Channels']
        for channel in channels:
            print "%s" % channel[0]
        # nothing else that uses showChannel follows, so we can exit here
        sys.exit(0) 


    if argObj.getLong("list") or len(pkgNames) or fullUpdate or dry_run:
        if fromDaemon:
            return batchRun(argObj.getLong("list"), pkgNames, fullUpdate, fromDaemon)
        try:
            sys.exit(batchRun(argObj.getLong("list"),
		              pkgNames, fullUpdate, dryRun = dry_run))
        except up2dateErrors.GPGVerificationError, e:
            # might as well be annoying and loud about it
            print
            print "************ GPG VERIFICATION ERROR ****************"
            print e
            print "****************************************************"
            print
            sys.exit(1)
        except up2dateErrors.FileNotFoundError, e:
            print  e.errmsg
            sys.exit(1)
        except up2dateErrors.GPGVerificationUnsignedPackageError,e:
            print e, "Aborting..."
            sys.exit(1)
        except up2dateErrors.CommunicationError, e:
            print _("There was a fatal error communicating with the server.  The message was:\n") + e.errmsg
            sys.exit(1)
        except up2dateErrors.RpmError, e:
            print _("There was a fatal RPM error.  The message was:\n") + e.errmsg
            sys.exit(1)
        except up2dateErrors.RpmInstallError, e:
            print _("There was a fatal RPM install error. The message was:\n") + e.errmsg
            sys.exit(1)
        except up2dateErrors.DependencyError, e:
            print _("There was a package dependency problem.  The message was:\n") + e.errmsg
            sys.exit(1)
        except up2dateErrors.UnsolvedDependencyError, e:
            print _("There was a package dependency problem.  The message was:\n") + e.errmsg
            sys.exit(1)
        except up2dateErrors.OutOfSpaceError, e:
            print _("There was an error installing the packages. The message was:\n") + e.errmsg
            sys.exit(1)
        except up2dateErrors.ConflictError, e:
            print e
            sys.exit(1)
            
    else:
        if hasGui:
	    try:
            	from up2date_client import gui
                nogui = 0
	    except RuntimeError:
                # if we fail to initialize the interface, fall back to tui
                nogui = 1
                
 	    if not nogui:
                wrapperUtils.warningCallback = gui.errorWindow
            	gui.main()	
            	sys.exit(0)
                
        print _("No interactive mode available")
        print _("Please specify either -l, -u, --nox, or package names as command line arguments.")
        argObj.ctx.printHelp()
        if fromDaemon:
            return 1
        else:
            sys.exit(1)
        
def ReportError(*args):
    sys.stderr.write("%s\n" % string.join(map(str, args)))

def showVersion(hasGui):
    if hasGui:
        try:
            from up2date_client import gui
            gui.showAbout()
        except:
            print _("Unable to open gui. Try specifying \"--nox\" as an option")
    else:
        print "Red Hat Update Agent v%s" % up2date.version()
        print "Copyright (c) 1999-2001 Red Hat, Inc."
        print _("Licensed under terms of the GPL.")


def faultError(hasGui,msg):
    errMsg = msg
    
    if hasGui:
        try:
            from up2date_client import gui
            gui.errorWindow(errMsg)
        except:
            print _("Unable to open gui. Try `up2date --nox`")
            print errMsg
    else:
        print errMsg



def whatprovides(depslist,returnlist=None):
    tmp_list = string.split(depslist, ",")
    deps_list=[]
    availlist = up2date.getAvailablePackageList()
    # a little text munging to make this commandline friendlier
    for i in tmp_list:
        i=string.strip(i)
        deps_list.append(i)
    try:
        provides = depSolver.solveDep(deps_list,availlist)
    except up2dateErrors.DependencyError:
        print "Unable to solve deps for  %s" %         deps_list       
        return None
    if returnlist:
        pkgnames = []
        for provide in provides:
            pkgnames.append(provide[0])
        return pkgnames
    pkgDict = up2date.avail_package_dict()
    for provide in provides:
        pkgString = "%s-%s-%s" % (provide[0], provide[1],provide[2])
        if cfg.readEntry("showChannels"):
            # print the channel name
            channelName = pkgDict["%s-%s-%s.%s" % (provide[0], provide[1],provide[2], provide[4])][6]
            print "%-40s%-30s" % (pkgString, channelName)
        else:
            print "%s" % pkgString


def printList(packageList):
    packageList.sort()
    pkgDict = up2date.avail_package_dict()
    for pkg in packageList:
        pkgString = "%s-%s-%s" % (pkg[0], pkg[1],pkg[2])
        if cfg.readEntry("showChannels"):
            channelName = pkgDict["%s-%s-%s.%s" % (pkg[0], pkg[1],pkg[2], pkg[4])][6]
            print "%-40s%-30s" % (pkgString, channelName)
        else:
            print "%s" % (pkgString)

    
def batchRun(onlyList, pkgNames, fullUpdate = 0, 
	    fromDaemon = 0, actionPkgs=None, dryRun=None):

    rpmCallback = wrapperUtils.RpmCallback()

    batch = up2dateBatch.BatchRun()
    batch.onlyList = onlyList
    batch.dryRunFlag = dryRun

    # quiet mode for rhn_check
    if fromDaemon:
        batch.printCallback = None
        batch.percentCallback = None
    else:
        batch.printCallback = wrapperUtils.printit
        batch.percentCallback = wrapperUtils.percent

    batch.listOfPkgNames = pkgNames
    batch.onlyList = onlyList
    batch.fromDaemon = fromDaemon
    batch.actionPkgs = actionPkgs
    batch.rpmCallback = rpmCallback.callback


    batch.run()

    # cases...
    # case 1: I specify a package to install, the package is availa
    #         I want the dep list, and the warning if it's found, but
    #         not the info about packages that were skipped unless it was
    #         one of the cmdline packages or it's deps

    # case 2: a full update... I want all the info
    #
    # case 3: actions... not sure...


    if len(batch.skippedPackages):
        wrapperUtils.printSkippedPackages(batch.skippedPackages)

    if len(batch.obsoletedPackages) and ( onlyList or dryRun):
        wrapperUtils.printObsoletedPackages(batch.obsoletedPackages)

    if len(batch.installedObsoletingPackages):
        wrapperUtils.printInstalledObsoletingPackages(batch.installedObsoletingPackages)

    if not batch.packagesToInstall:
        print _("None of the packages you requested were found, or they are already updated.")
	# if we got no updates, but packages we skipped, raise an exception indicating that

        # FIXME: insert code here to determine if packages were on package skip, file skip, or
        # skipped because of config stuff... probabaly need to add code to PackageList to expose
        # that info individually and then make BatchRun know that...
#	if fromDaemon:
#	    if len(skippedPackagesPkgSkipList):
#	        raise up2dateErrors.SkipListError("The following packages were on your skip list and could not be installed: %s" % skippedPackagesPkgSkipList, skippedPackagesPkgSkipList)
#	    if len(skippedPackagesFileConfigSkipList):
#		raise up2dateErrors.FileConfigSkipListError("The following packages were on your skip list and could not be installed: %s" % skippedPackagesFileConfigSkipList, skippedPackagesFileConfigSkipList)
	return 1

    #FIXME:? should batch run do this itself?
    if len(batch.depPackages):
        wrapperUtils.printDepPackages(batch.depPackages)


    #FIXME: maybe we should split Batch.run() into Batch.setup(), Batch.fetch(), and
    # Batch.install() so we can handle the errors better?
    
    if batch.kernelsToInstall and lilocfg:
        try:
            up2date.installBootLoader(batch.kernelsToInstall)
        except (lilocfg.LiloConfError, lilocfg.LiloInstallError),  info:
            print "%s" % info
            return 1

    # we're fine up to this point...
    return 0
            
        
if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        print "\nAborted."
        sys.exit(1)
    except OSError, e:
        print _("An unexpected OS error occurred: %s") % e
        sys.exit(1)
    except IOError, e:
        print _("There was some sort of I/O error: %s") % e
        sys.exit(1)
