#!/usr/bin/python -u
#
# Copyright (c) 1999,2000 Red Hat, Inc.
# Red Hat Update Agent is licensed under the GPL.
# $Id: main.py,v 1.26 2000/03/09 17:05:58 pbrown Exp $

import sys
import os
import re
sys.path.append("/usr/share/up2date")
import urllib, string
from threading import Thread

def passPackageList(pkgListFile):
    # okay, noe the client simply read the contents of the
    # pkgListFile and tries to throw it into the Unix domain
    # socket where something else should be waiting for it
    from socket import *
    import time
    
    # Probably these should be config options later, but for now we'd better
    # not let the users play with these
    sock_path = "/var/run/up2date.sock"
    sock_timeout = 15

    sock = socket(AF_UNIX, SOCK_STREAM)
    if sock < 0:
        print "up2date client: Error processing data"
        print "Could not create a socket for sending data to the parent process"
        return -1

    while sock.connect_ex(sock_path) != 0:
        # wait on the parent to create that socket for us
        time.sleep(1)
        sock_timeout = sock_timeout - 1
        if sock_timeout <= 0:
            return -1
        
    # we're connected okay
    if not os.access(pkgListFile, os.R_OK):
        print "Cannot open package file \"%s\" for "
        "reading.\n  Do you have sufficient "
        "permissions?" % pkgListFile
        return -1
        
    # you gotta love python
    dataStr = open(pkgListFile, 'r').read()

    need_write = len(dataStr)
    while 1:
        try:
            w = os.write(sock.fileno(), dataStr)
        except:
            print "Could not write data to the parent socket"
            break
        if w >= 0:
            need_write = need_write - w
        else:
            # some weird error
            print "Could not write %d bytes to parent's socket" % (need_write,)
        if need_write <= 0:
            # we're done
            break
    if need_write > 0:
        # could not write the whole thing
        return -1
    sock.close()
    return 0

def showHelp():
    print "Usage: up2date [options] [pkgnames]"
    print ""
    print "Available command line options:"
    print "-a <auth>, --auth=<auth>        - override authorization information"
    print "-b, --batch                     - batch mode (no GUI, email results)"
    print "-l, --list                      - list packages available for retrieval"
    print "-p <list>, --packagelist=<list> - a list of packages to retrieve (internal)"
    print "-u                              - updates disc mode"
    print "-v, --version                   - display Update Agent version"
    print "-h, --help                      - this help"
    print ""
    print "When operating in batch mode, specifying package names on the command"
    print "line will attempt to retrieve (and possibly install) those packages,"
    print "bypassing package selection.  Packages may be requested BY NAME ONLY,"
    print "i.e. bind or apache.  Version, release, and architecture information will"

    print "be determined by the Update Agent automatically."
    

if __name__ == "__main__":
    import getopt
    
    batch = 0
    authStr = ""
    pkgListFile = ""
    updatesMode = 0
    onlyList = 0
    pkgNames = []
    VERSION = 1.13 # UPDATE ME WHEN SPEC FILE VERSION CHANGES!!!
    
    try:
	optlist, args = getopt.getopt(sys.argv[1:], 
			       'bhluvp:a:', [ 'batch', 'help', 'list',
                                              'version', 'auth=',
                                              'packagelist=' ])

    except getopt.error, msg:
	print("Error parsing command line arguments: %s" % msg)
        showHelp()
	sys.exit()

    if args:
        pkgNames = args
	
    for opt in optlist:
	if opt[0] == '-b' or opt[0] == '--batch':
	    batch = 1
	elif opt[0] == '-a' or opt[0] == '--auth=':
	    authStr = opt[1]
	elif opt[0] == '-p' or opt[0] == '--packagelist=':
	    pkgListFile = opt[1]
	elif opt[0] == '-u':
	    updatesMode = 1
	elif opt[0] == '-h' or opt[0] == '--help':
            showHelp()
	    sys.exit()
        elif opt[0] == '-l' or opt[0] == '--list':
            onlyList = 1
            batch = 1
        elif opt[0] == '-v' or opt[0] == '--version':
            print "Red Hat Update Agent", VERSION
            sys.exit()
        

    if os.geteuid() != 0:
	print "You must run Update Agent as root."
	sys.exit(-1)

    
    # stop gnome from stealing argument processing
    for arg in sys.argv[1:]:
      	sys.argv.remove(arg)
    sys.argc = 1
    
    # This is a hack. Check to see if we need to force batch mode
    if not batch:
	try:
	    error = os.system("netscape -version >/dev/null 2>&1")
	    if error:
		batch = 1
	except:
	    batch = 1
    
    if not batch:
	from gui import Gui
	from os import environ
	from gtk import mainloop, threads_enter, threads_leave

	# first thing we need to do is check for proper mime types
	# in this user's .mailcap
	try:
	    f = open("%s/.mailcap" % environ['HOME'], "r")
	except:
            # XXX: what if we don't have write permission? --gafton
	    f = open("%s/.mailcap" % environ['HOME'], "a")
	    f.close()
	    f = open("%s/.mailcap" % environ['HOME'], "r")

	found = 0
	for line in f.readlines():
	    if re.match("application/redhat-package-list", line):
		found = 1
		break
	f.close()
	if not found:
	    f = open("%s/.mailcap" % environ['HOME'], "a")
	    f.write("#mailcap entry added by Red Hat Update Agent\n")
	    f.write("application/redhat-package-list;/usr/sbin/up2date -p %s\n")
	    f.close()

	class GtkMainThread (Thread):
	    def run (self):
		self.setName ("gtk_main")
		threads_enter ()
		mainloop ()
		threads_leave ()

	if pkgListFile != "":
            if passPackageList(pkgListFile) != 0:
                sys.exit(-1)
            sys.exit(0)
            
	# in gui mode, we let the Gui handle all interactions
	# (including creation) with the Client class.
	g = Gui(authStr, updatesMode)
        m = GtkMainThread ()
	m.start ()
    else:
	from client import Client
	# in batch mode, the client does nothing but
	# follow orders from outside.
	c = Client(authStr)
    
	if pkgListFile == "":
	    c.getPackageList()
                
	    c.removeSkipPackages(c.pkgList)
	    c.removeInstalledPackages(c.pkgList, 
				      c.cfg.readEntry("retrieveNew"))
            if pkgNames:
                c.selectPackages(pkgNames)

            if onlyList:
                if onlyList == []:
                    print "No available packages."
                else:
                    print "Available packages:\n"
                    for pkg in c.pkgList:
                        print "%s" % re.sub(" ", "-", pkg, "r")
                    sys.exit(0)

	    if len(c.pkgList) == 0:
		c.addReply("No packages to install, quitting.")
		c.finishUp()

        else:
	    f = open(pkgListFile, 'r')
	    stateData = f.readline()
	    stateData = urllib.unquote_plus(stateData)
	    c.state = stateData
	    f.readline() # throw away blank separator line
	    for line in f.readlines():
		name, epoch, version, release = string.split(line)
		c.pkgList.append("%s %s %s %s" % (name, epoch, version, release))
	    f.close()

	c.retrieveHeaders(c.pkgList)
	c.removeSkipFiles(c.pkgList)

	if len(c.pkgList) == 0:
	    c.addReply("No packages to install, quitting.")
	    c.finishUp()

	c.dryRun()

	c.checkFreeDiskSpace()

	c.retrievePackages()

	if not c.cfg.readEntry("retrieveOnly"):
	    c.installPackages()

        if not c.cfg.readEntry("retrieveOnly"):
            c.addReply("\nThe following packages were installed:\n")
        else:
            c.addReply("\nThe following packages were retrieved:\n")

        for p in c.pkgList:
            name, epoch, version, release = string.split(p)
            c.addReply("%s-%s-%s" % (name, version, release))

	if (not c.cfg.readEntry("retrieveOnly") and 
	    not c.cfg.readEntry("keepAfterInstall")):
	    c.deletePackageFiles()

	c.addReply("\nDone.")
	c.finishUp()
