#!/usr/bin/python
#
# GUI for Update Agent
# Copyright (c) 1999-2002 Red Hat, Inc.  Distributed under GPL.
#
# Authors:
#    Preston Brown <pbrown@redhat.com>
#    Adrian Likins <alikins@redhat.com>

import os
import sys
import time
import string


import gtk
from socket import gethostname
from gtk import TRUE
from gtk import FALSE
import gnome, gnome.ui
# XXX: why is this import necessary? We use only gtk.glade in the code...
from gtk import glade
import gobject
import signal
import rpm
import lilocfg
import xmlrpclib


sys.path.append("/usr/share/rhn/up2date_client")

from rhpl.translate import _, N_
gtk.glade.bindtextdomain("up2date", "/usr/share/locale")

import progress
import checklist
import up2dateErrors
import up2dateAuth
import up2date
import config
import rhnChannel
import packageList
import gpgUtils
import rhnErrata
import up2dateUtils
import rhnreg
import hardware
import rpmUtils
import up2dateLog
import wrapper


# wrap a long line...
def wrap_line(line, max_line_size = 100):
    if len(line) < max_line_size:
        return line
    ret = []
    l = ""
    for w in string.split(line):
        if not len(l):
            l = w
            continue
        if len(l) > max_line_size:
            ret.append(l)
            l = w
        else:
            l = "%s %s" % (l, w)
    if len(l):
        ret.append(l)
    return string.join(ret, '\n')

# wrap an entire piece of text
def wrap_text(txt):
    return string.join(map(wrap_line, string.split(txt, '\n')), '\n')

def addFrame(dialog):
    contents = dialog.get_children()[0]
    dialog.remove(contents)
    frame = gtk.Frame()
    frame.set_shadow_type(gtk.SHADOW_OUT)
    frame.add(contents)
    dialog.add(frame)

class MessageWindow:
    def getrc (self):
        return self.rc

    def hide(self):
        self.dialog.hide()
        self.dialog.destroy()
        gtk.main_iteration()

    def __init__ (self, title, text, type="ok", default=None, parent=None):
        self.rc = None
        if type == 'ok':
            buttons = gtk.BUTTONS_OK
            style = gtk.MESSAGE_INFO
        elif type == 'warning':
            buttons = gtk.BUTTONS_OK
            style = gtk.MESSAGE_WARNING
        elif type == 'okcancel':
            buttons = gtk.BUTTONS_OK_CANCEL
            style = gtk.MESSAGE_WARNING
        elif type == 'yesno':
            buttons = gtk.BUTTONS_YES_NO
            style = gtk.MESSAGE_QUESTION
        elif type == "error":
            buttons = gtk.BUTTONS_OK
            style = gtk.MESSAGE_ERROR
        elif type == "question":
            buttons = gtk.BUTTONS_YES_NO
            style = gtk.MESSAGE_QUESTION

        # this seems to be wordwrapping text passed to
        # it, which is making for ugly error messages
        self.dialog = gtk.MessageDialog(parent, 0, style, buttons, text)
        self.dialog.label.set_line_wrap(FALSE)
        if default == "no":
            self.dialog.set_default_response(0)
        elif default == "yes" or default == "ok":
            self.dialog.set_default_response(1)
        else:
            self.dialog.set_default_response(0)

        addFrame(self.dialog)
        self.dialog.set_position (gtk.WIN_POS_CENTER)
        self.dialog.show_all ()
        rc = self.dialog.run()
        if rc == gtk.RESPONSE_OK or rc == gtk.RESPONSE_YES:
            self.rc = 1
        elif (rc == gtk.RESPONSE_CANCEL or rc == gtk.RESPONSE_NO
            or rc == gtk.RESPONSE_CLOSE):
            self.rc = 0
        self.dialog.destroy()

class ErrorDialog(MessageWindow):
    def __init__ (self, text, parent=None):
        MessageWindow.__init__(self,_("Error:"),
                               text,
                               type="error",
                               parent=parent)

class WarningDialog(MessageWindow):
    def __init__ (self, text, parent=None):
        MessageWindow.__init__(self, _("Warning:"),
                               text,
                               type="warning",
                               parent=parent)

class OkDialog(MessageWindow):
    def __init__ (self, text, parent=None):
        MessageWindow.__init__(self, _("OK dialog:"),
                               text,
                               type="ok",
                               parent=parent)

    
class YesNoDialog(MessageWindow):
    def __init__ (self, text, parent=None):
        MessageWindow.__init__(self,_("Yes/No dialog:"),
                               text,
                               type="yesno",
                               parent=parent)

class QuestionDialog(MessageWindow):
    def __init__ (self, text, parent=None):
        MessageWindow.__init__(self,_("Question dialog:"),
                               text,
                               type="question",
                               parent=parent)


class AboutWindow:
    def __init__(self):
        self.window = gnome.ui.About(_("Red Hat Update Agent"),
                                     up2dateUtils.version(),
                                     "Copyright (c) 1999-2002 Red Hat, Inc.\n" +
                                     _("This software is distributed under the GPL\n" \
                                       "Please Report bugs to Red Hat's Bug Tracking " \
                                       "System: http://bugzilla.redhat.com/bugzilla/"),
                                     _("Update Agent - a program for updating packages on Red Hat Linux"),
                                     ["Preston Brown <pbrown@redhat.com>",
                                      "Adrian Likins <alikins@redhat.com>",
                                      "Cristian Gafton <gafton@redhat.com>"],
                                     (_("This software is distributed under the GPL.  Please Report bugs to Red Hat's Bug Tracking System: http://bugzilla.redhat.com/bugzilla/"),))
        self.window.connect("destroy", self.on_close)
        self.window.show()
        while self.window:
            gtk.main_iteration()

    def on_close(self, *data):
        self.window = None


def showAbout():
    dlg = AboutWindow()
    return
    
forceRegister = 0

class Gui:

    def __init__(self):
        self.gotPackages = FALSE
        self.gotSkippedPackages = FALSE

        self.cfg = config.initUp2dateConfig()
        self.log = up2dateLog.initLog()

        
        self.xml = gtk.glade.XML("/usr/share/rhn/up2date_client/gui.glade", "mainWin", domain="up2date")
        self.xml.signal_autoconnect (
            { "onDruidCancel" : self.onDruidCancel,
              "onStartPageNext" : self.onStartPageNext,
              "onPrivacyPagePrepare": self.onPrivacyPagePrepare,
              "onTermsAndConditionsPagePrepare": self.onTermsAndConditionsPagePrepare,
              "onLoginPagePrepare" : self.onLoginPagePrepare,
              "onLoginPageNext" : self.onLoginPageNext,
              "onLoginPageBack" : self.onLoginPageBack,
              "onCreateNewAccountButtonToggled": self.onCreateNewAccountButtonToggled,
              "onUseExistingAccountButtonToggled": self.onCreateNewAccountButtonToggled,
              "onProductPagePrepare" : self.onProductPagePrepare,
              "onProductPageNext" : self.onProductPageNext,
              "onProductPageBack" : self.onProductPageBack,
              "onProfilePagePrepare" : self.onProfilePagePrepare,
              "onProfilePageNext" : self.onProfilePageNext,
              "onProfilePageBack" : self.onProfilePageBack,
              "onEnableHardwareButtonToggled" : self.onEnableHardwareButtonToggled,
              "onAutoUpdateUp2dateButtonToggled" : self.onAutoUpdateUp2dateButtonToggled,
              "onRegPackagePagePrepare" : self.onRegPackagePagePrepare,
              "onRegPackagePageBack" : self.onRegPackagePageBack,
              "onEnableRpmButtonToggled" : self.onEnableRpmButtonToggled,
              "onSendPageBack" : self.onSendPageBack,
              "onSendPageNext" : self.onSendPageNext,
              "onRegFinishPagePrepare" : self.onRegFinishPagePrepare,
              "onChannelsPagePrepare" : self.onChannelsPagePrepare,
              "onChannelsPageNext" : self.onChannelsPageNext,
              "onSkippedPagePrepare" : self.onSkippedPagePrepare,
              "onSkippedPageNext" : self.onSkippedPageNext,
              "onPackagePagePrepare" : self.onPackagePagePrepare,
              "onPackagePageNext" : self.onPackagePageNext,
              "onPackagePageBack" : self.onPackagePageBack,
              "onAvailablePackagePagePrepare" : self.onAvailablePackagePagePrepare,
              "onAvailablePackagePageNext" : self.onAvailablePackagePageNext,
              "onDependencyPagePrepare" : self.onDependencyPagePrepare,
              "onDependencyPageBack" : self.onDependencyPageBack,
              "onRetrievalPagePrepare" : self.onRetrievalPagePrepare,
              "onRetrievalPageNext" : self.onRetrievalPageNext,
              "onRetrievalPageBack" : self.onRetrievalPageBack,
              "onInstallPagePrepare": self.onInstallPagePrepare,
              "onInstallPageBack": self.onInstallPageBack,
              "onFinishPagePrepare" : self.onFinishPagePrepare,
              "onFinishPageFinish" : self.onFinishPageFinish } )
               
        self.initPrivacy = FALSE
        self.initTermsAndConditions = FALSE
        self.showTermsAndConditions = FALSE
        self.initPackages = FALSE
        self.initProfile = FALSE
        self.alreadyRegister = FALSE
        self.oemInfo = {}
        self.productInfo = {}
        self.pkgIndex = 0
        self.updateUp2date = None
        self.installedPackages = None

        self.pkgList = []
        self.selectedPkgList = []
        self.skipPkgList = []
        self.pkgsSelected = FALSE
        
        self.druid = self.xml.get_widget("druid")
        self.mainWin = self.xml.get_widget("mainWin")
        self.mainWin.connect("delete-event", gtk.mainquit)
        self.mainWin.connect("hide", gtk.mainquit)
        self.setupSkippedList()
        self.setupPackageList()
        self.setupRegPackageList()
        self.setupChannelList()
        self.setupAvailablePackageList()

        # background on finished page
        #box = self.xml.get_widget("finishEventBox")
        color = gtk.gdk.color_parse("#cc0000")
        startpage = self.xml.get_widget("startPage")
        startpage.set_bg_color(color)
        
        self.mainWin.show_all()
        self.xml.get_widget("packagesFinishedLabel").set_text("...")
        self.xml.get_widget("installingFinishedLabel").set_text("...")

        if self.detectStateFile():
            self.openPackageStateFile()
            self.deleteStateFile()
            if len(self.skipPkgList):
                self.druid.set_page(self.xml.get_widget("skippedPage"))
            else:
                self.druid.set_page(self.xml.get_widget('packagePage'))

    def onDruidCancel(self, dummy):
        # FIXME: this shouldne be neded
        # this only exits the innermost mainloop
        # and I dont have a way to determine what level of mainloop
        # i'm at, so I can do a gtk.quit_add()
        
        gtk.mainquit()
        # so less be harsh and really quit...
        sys.exit()


    def fatalError(self, error, wrap=1):
        self.setArrowCursor()
        # FIXME
        if wrap:
            text = wrap_text(error)
        else:
            text = error

        dlg = ErrorDialog(text,self.mainWin)
        gtk.mainquit()
        sys.exit(1)



    def setBusyCursor(self):
        # gtk 1.2
#        cursor = gtk.cursor_new (GDK.WATCH)
        # gtk 2.0
        cursor = gtk.gdk.Cursor(gtk.gdk.WATCH)
        self.mainWin.window.set_cursor(cursor)
        while gtk.events_pending():
            gtk.mainiteration(FALSE)


    def setArrowCursor(self):
        # gtk 1.2
#        cursor = gtk.cursor_new (GDK.LEFT_PTR)
        # gtk 2.0
        cursor = gtk.gdk.Cursor(gtk.gdk.LEFT_PTR)
        self.mainWin.window.set_cursor(cursor)
        while gtk.events_pending():
            gtk.mainiteration(FALSE)
            
    def __updateSelectedSizeLabel(self, sizeLabel, state, rowData):
        if state == 0:
            # weird logic, dont subtract the package size from the total
            # if we never added it...
            if not up2date.isPackageCached(rowData):
                self.totalSelectedSize = self.totalSelectedSize - int(rowData[5])
            self.pkgsSelected = self.pkgsSelected - 1
        else:
            if not up2date.isPackageCached(rowData):
                self.totalSelectedSize = self.totalSelectedSize + int(rowData[5])
            self.pkgsSelected = self.pkgsSelected + 1
        sizeLabel.set_text("%d kB" % (self.totalSelectedSize / 1024))
                
    def updateSelectedSize(self, state, rowData):
        sizeLabel = self.xml.get_widget("sizeLabel")

        self.__updateSelectedSizeLabel(sizeLabel, state, rowData)
        if not self.cfg["showAvailablePackages"]:
            if self.pkgsSelected:
                self.druid.set_buttons_sensitive(TRUE, TRUE, TRUE, TRUE)
            else:
                self.druid.set_buttons_sensitive(TRUE, FALSE, TRUE, TRUE)
        

    def updateAvailableSelectedSize(self, state, rowData):
        sizeLabel = self.xml.get_widget("availableSizeLabel")
        self.__updateSelectedSizeLabel(sizeLabel, state, rowData)

        if self.pkgsSelected:
            self.druid.set_buttons_sensitive(TRUE, TRUE, TRUE, TRUE)
        else:
            self.druid.set_buttons_sensitive(TRUE, FALSE, TRUE, TRUE)
        
            
    def setupSkippedList(self):
        self.currentRow = -1
        window = self.xml.get_widget("skippedWindow")

        self.skippedArea = checklist.CheckList(6)
        self.skippedArea.set_column_title(1, _("Package Name"))
        #self.skippedArea.set_column_min_width(1, 200)
        self.skippedArea.set_column_title(2, _("Version"))
        self.skippedArea.set_column_min_width(2, 80)
        self.skippedArea.set_column_title(3, _("Old Version"))
        self.skippedArea.set_column_min_width(3, 80)
        self.skippedArea.set_column_title(4, _("Arch"))
        self.skippedArea.set_column_min_width(4, 50)
        self.skippedArea.set_column_title(5, _("Size"))
        self.skippedArea.set_column_min_width(5, 50)
        self.skippedArea.set_column_title(6, _("Reason Skipped"))
        self.skippedArea.set_column_min_width(4, 50)
        self.skippedArea.column_titles_show()
        #self.skippedArea.focus_row = -1

        self.skippedArea.connect("select_row", self.showPackageInfo,
                                 (self.xml.get_widget("skippedPackageTextArea")))
        window.add(self.skippedArea)

        self.xml.get_widget("skippedSelectAllButton").connect("toggled",
                                                              self.selectAll)
        self.xml.get_widget("advisoryButton").connect("clicked",
                                                      self.showAdvisory,
                                                      self.skippedArea)

    def onPrivacyPagePrepare(self, page, dummy):
        try:
            rhnreg.getCaps()
        except xmlrpclib.Fault, f:
            self.fatalError(f.faultString,wrap=0)
            sys.exit(1)
            
        self.xml.get_widget("privacyPage").emit_stop_by_name("prepare")
        self.xml.get_widget("mainWin").set_title(_("Up2date - Privacy Information"))
        if not self.initPrivacy:
            self.setBusyCursor()

            privacyArea = self.xml.get_widget("privacyArea")
            #privacyArea.delete_text(0, privacyArea.get_length())
            try:
                text = rhnreg.privacyText()
            except up2dateErrors.CommunicationError, e:
                self.mainWin.hide()
                self.fatalError(_("Fatal error retrieving privacy statement:\n") + e.errmsg)

            buffer = gtk.TextBuffer(None)
            buffer.set_text(text)

            privacyArea.set_buffer(buffer)
            self.initPrivacy = TRUE
            self.setArrowCursor()


    def onTermsAndConditionsPagePrepare(self, page, dummy):
        if not self.showTermsAndConditions:
            druid = self.xml.get_widget("druid")
            druid.set_page(self.xml.get_widget("loginPage"));
            return TRUE
            
        self.xml.get_widget("termsAndConditionsPage").emit_stop_by_name("prepare")
        self.xml.get_widget("mainWin").set_title(_("Up2date - Terms And Conditions"))
        if not self.initTermsAndConditions:
            self.setBusyCursor()

            termsAndConditionsArea = self.xml.get_widget("termsAndConditionsArea")
            try:
                text = """
                Insert T&C's downloaded from the server here"""
                print "#FIXME"
#                rhnreg.termsAndConditions()
            except up2dateErrors.CommunicationError, e:
                self.mainWin.hide()
                self.fatalError(_("Fatal error retrieving privacy statement:\n") + e.errmsg)

            buffer = gtk.TextBuffer(None)
            buffer.set_text(text)

            termsAndConditionsArea.set_buffer(buffer)
            self.initPrivacy = TRUE
            self.setArrowCursor()
        

    def onLoginPagePrepare(self, page, dummy):
        self.xml.get_widget("loginPage").emit_stop_by_name("prepare")
        self.createNewAccount = self.xml.get_widget("createNewAccountButton").get_active()
        self.xml.get_widget("mainWin").set_title(_("Up2date - Login Page"))
        pass

    def onCreateNewAccountButtonToggled(self, button):
        self.createNewAccount = self.xml.get_widget("createNewAccountButton").get_active()
        self.xml.get_widget("mainWin").set_title(_("Up2date - New Account Creation"))

        if not self.createNewAccount:
            self.xml.get_widget("loginPasswordConfirmLabel").set_sensitive(FALSE)
            self.xml.get_widget("loginPasswordConfirmEntry").set_sensitive(FALSE)
            self.xml.get_widget("loginEmailLabel").set_sensitive(FALSE)
            self.xml.get_widget("loginEmailEntry").set_sensitive(FALSE)
        else:
            self.xml.get_widget("loginPasswordConfirmLabel").set_sensitive(TRUE)
            self.xml.get_widget("loginPasswordConfirmEntry").set_sensitive(TRUE)
            self.xml.get_widget("loginEmailLabel").set_sensitive(TRUE)
            self.xml.get_widget("loginEmailEntry").set_sensitive(TRUE)

    def onLoginPageBack(self, page, dummy):
        self.xml.get_widget("druid").set_page(self.xml.get_widget("privacyPage"))
        return TRUE
        
            

    def onLoginPageNext(self, page, dummy):
        pw1 = self.xml.get_widget("loginPasswordEntry")
        pw2 = self.xml.get_widget("loginPasswordConfirmEntry")
        uname = self.xml.get_widget("loginUserEntry")
        email = self.xml.get_widget("loginEmailEntry")
        druid = self.xml.get_widget("druid")
        
        self.alreadyRegistered = None

        # validate / check user name
        if uname.get_text() == "":
            self.setArrowCursor()
            dlg = ErrorDialog(_("You must enter a user name."),
                              parent=self.mainWin)
            uname.grab_focus()
            return TRUE
        # they didn't enter a password
        if pw1.get_text() == "" and not self.createNewAccount:
            self.setArrowCursor()
            dlg = ErrorDialog(_("You must enter and verify a password."),
                              parent=self.mainWin)
            pw1.grab_focus()
            return TRUE

        if self.createNewAccount:
            if pw1.get_text() == "" or pw2.get_text() == "":
                self.setArrowCursor()
                dlg = ErrorDialog(_("You must enter and verify a password."),
                                  parent=self.mainWin)
                pw1.grab_focus()
                return TRUE

            if not pw1.get_text() == pw2.get_text():
                self.setArrowCursor()
                dlg = WarningDialog(_("The two passwords you entered do not match.\nPlease re-type the second password."),
                                    parent=self.mainWin)
                pw2.set_text("")
                pw2.grab_focus()
                return TRUE

            # verify they gave an email address
            if not rhnreg.validateEmail(email.get_text()):
                self.setArrowCursor()
                dlg = ErrorDialog(_("You must enter a valid e-mail address."),
                                  parent=self.mainWin)
                email.set_text("")
                email.grab_focus()
                return TRUE


            try:
                self.alreadyRegistered = rhnreg.reserveUser(uname.get_text(),
                                                            pw1.get_text())
            except up2dateErrors.ValidationError, e:
                self.setArrowCursor()
                dlg = ErrorDialog(wrap_text(_("The server indicated an error:\n") + e.errmsg),
                                  parent=self.mainWin)
                uname.grab_focus()
                return TRUE
            except up2dateErrors.CommunicationError, e:
                self.setArrowCursor()
                self.fatalError(_("There was an error communicating with the registration server.  The message was:\n") + e.errmsg)

                # skip over the personal information (productPage) if the user
                # has already registered with redhat.com.
                if self.alreadyRegistered:
                    druid.set_page(self.xml.get_widget("profilePage"));
                    return TRUE
                
        if not self.createNewAccount:
            try:
                self.alreadyRegistered = rhnreg.reserveUser(uname.get_text(),
                                                            pw1.get_text())
            except up2dateErrors.ValidationError, e:
                self.setArrowCursor()
                dlg = ErrorDialog(wrap_text(_("The server indicated an error:\n") + e.errmsg),
                                  parent=self.mainWin)
                uname.grab_focus()
                return TRUE
            except up2dateErrors.CommunicationError, e:
                self.setArrowCursor()
                self.fatalError(_("There was an error communicating with the registration server.  The message was:\n") + e.errmsg)
            
            druid.set_page(self.xml.get_widget("profilePage"));
            return TRUE

        return FALSE
        



    def onProductPagePrepare(self, page, dummy):
        self.xml.get_widget("productPage").emit_stop_by_name("prepare")
        self.xml.get_widget("mainWin").set_title(_("Up2date - Product Information Page"))
        self.setBusyCursor()

        self.xml.get_widget("regInfoLabel").set_text(_("All information is optional."))
        self.xml.get_widget("redLabel").hide()

        label = self.xml.get_widget("redLabel")
        label.set_text("")
        style = label.get_style().copy()
        label = self.xml.get_widget("firstNameLabel")
        label.set_style(style)
        label = self.xml.get_widget("lastNameLabel")
        label.set_style(style)
        label = self.xml.get_widget("address1Label")
        label.set_style(style)
        label = self.xml.get_widget("cityLabel")
        label.set_style(style)
        label = self.xml.get_widget("stateLabel")
        label.set_style(style)
        label = self.xml.get_widget("zipLabel")
        label.set_style(style)
        label = self.xml.get_widget("countryLabel")
        label.set_style(style)
        label = self.xml.get_widget("phoneLabel")
        label.set_style(style)

        self.setArrowCursor()

        
    def onProductPageNext(self, page, dummy):
        self.productInfo = {}
        self.setBusyCursor()
        
        self.productInfo['title'] = self.xml.get_widget("titleCombo").entry.get_text()
        entry = self.xml.get_widget("firstNameEntry")

        self.productInfo['first_name'] = entry.get_text()
        entry = self.xml.get_widget("lastNameEntry")

        self.productInfo['last_name'] = entry.get_text()

        self.productInfo['company'] = self.xml.get_widget("companyEntry").get_text()

        self.productInfo['position'] = self.xml.get_widget("positionEntry").get_text()

        entry = self.xml.get_widget("address1Entry")
        self.productInfo['address1'] = entry.get_text()
        
        self.productInfo['address2'] = self.xml.get_widget("address2Entry").get_text()

        entry = self.xml.get_widget("cityEntry")
        self.productInfo['city'] = entry.get_text()

        entry = self.xml.get_widget("stateCombo").entry
        self.productInfo['state'] = entry.get_text()

        entry = self.xml.get_widget("zipEntry")
        self.productInfo['zip'] = entry.get_text()

        entry = self.xml.get_widget("countryCombo").entry
        self.productInfo['country'] = entry.get_text()

        entry = self.xml.get_widget("phoneEntry")
        self.productInfo['phone'] = entry.get_text()

        self.productInfo['fax'] = self.xml.get_widget("faxEntry").get_text()

        button = self.xml.get_widget("emailContactButton")
        if button.get_active():
            self.productInfo['contact_email'] = 1
        else:
            self.productInfo['contact_email'] = 0

        # validate mail contact
        button = self.xml.get_widget("mailContactButton")
        if (button.get_active() and
            (self.xml.get_widget("firstNameEntry").get_text() == "" or
             self.xml.get_widget("lastNameEntry").get_text() == "" or
             self.xml.get_widget("address1Entry").get_text() == "" or
             self.xml.get_widget("cityEntry").get_text() == "" or
             self.xml.get_widget("stateCombo").entry.get_text() == "" or
             self.xml.get_widget("zipEntry").get_text() == "")):
            self.setArrowCursor()
            dlg = ErrorDialog(_("In order to receive communication by mail from Red Hat, you must fill out your\nfull name and address."), parent=self.mainWin)
            return TRUE

        if button.get_active():
            self.productInfo['contact_mail'] = 1
        else:
            self.productInfo['contact_mail'] = 0

        # validate information for phone contact
        button = self.xml.get_widget("phoneContactButton")
        if (button.get_active() and
            (self.xml.get_widget("phoneEntry").get_text() == "" or
             self.xml.get_widget("firstNameEntry").get_text() == "")):
            self.setArrowCursor()
            dlg = ErrorDialog(_("In order to have Red Hat contact you by phone, you must provide\nat least phone number and a name."), parent=self.mainWin)
            if self.xml.get_widget("firstNameEntry").get_text() == "":
                self.xml.get_widget("firstNameEntry").grab_focus()
            else:
                self.xml.get_Widget("phoneEntry").grab_focus()
            return TRUE

        if button.get_active():
            self.productInfo['contact_phone'] = 1
        else:
            self.productInfo['contact_phone'] = 0

        # validate information for phone contact
        button = self.xml.get_widget("faxContactButton")
        if (button.get_active() and
            (self.xml.get_widget("faxEntry").get_text() == "" or
             self.xml.get_widget("firstNameEntry").get_text() == "")):
            self.setArrowCursor()
            dlg = ErrorDialog(_("In order to have Red Hat contact you by fax, you must provide\nat least fax number and a name."), parent=self.mainWin)
            if self.xml.get_widget("firstNameEntry").get_text() == "":
                self.xml.get_widget("firstNameEntry").grab_focus()
            else:
                self.xml.get_widget("faxEntry").grab_focus()
            return TRUE
        
        if button.get_active():
            self.productInfo['contact_fax'] = 1
        else:
            self.productInfo['contact_fax'] = 0
        
        button = self.xml.get_widget("utbContactButton")
        if button.get_active():
            self.productInfo['newsletter'] = 1
        else:
            self.productInfo['newsletter'] = 0

        button = self.xml.get_widget("specialContactButton")
        if button.get_active():
            self.productInfo['special_offers'] = 1
        else:
            self.productInfo['special_offers'] = 0

        # in the optional case where nothing has been entered,
        # fix up fields that had default choices:
        if self.xml.get_widget("firstNameEntry").get_text() == "":
            self.productInfo['title'] = ""
            self.productInfo['state'] = ""
            self.productInfo['country'] = ""
            
        self.setArrowCursor()

    def onProductPageBack(self, page, dummy):
        self.xml.get_widget("druid").set_page(self.xml.get_widget("loginPage"))
        return TRUE
        


    def onProfilePagePrepare(self, page, dummy):
        self.xml.get_widget("profilePage").emit_stop_by_name("prepare")
        self.xml.get_widget("mainWin").set_title(_("Up2date - Hardware Profile"))
        self.sendHardware = self.xml.get_widget("enableHardwareButton").get_active()
        self.setBusyCursor()
        
        if not self.initProfile:
            hostname = gethostname()

            if string.find(hostname, "localhost") == -1:
                self.xml.get_widget("profileNameEntry").set_text(hostname)

            # Read all hardware in
            self.hardware = hardware.Hardware()
            
            for hw in self.hardware:
                if hw['class'] == 'CPU':
                    label = self.xml.get_widget("cpuLabel")
                    label.set_text(hw['model'])
                    label = self.xml.get_widget("speedLabel")
                    label.set_text(_("%d MHz") % hw['speed'])
                elif hw['class'] == 'MEMORY':
                    label = self.xml.get_widget("ramLabel")
                    try:
                        label.set_text(_("%s megabytes") % hw['ram'])
                    except:
                        pass

                elif hw['class'] == 'NETINFO':
                    label = self.xml.get_widget("hostnameLabel")
                    try:
                        label.set_text(hw['hostname'])
                    except:
                        pass
                    label = self.xml.get_widget("ipLabel")
                    try:
                        label.set_text(hw['ipaddr'])
                    except:
                        pass

            autoUpdateButton = self.xml.get_widget("autoUpdateUp2dateButton")

            # if the server doesnt support this, ignore it
            self.autoUpdate = 1
            if self.cfg['supportsAutoUp2dateOption'] == 0:
                self.autoUpdate = None
                autoUpdateButton.hide()

            label = self.xml.get_widget("versionLabel")
            try:
                distversion = up2dateUtils.getVersion()
            except up2dateErrors.RpmError, e:
                self.fatalError(e.errmsg)
                
            label.set_text(distversion)

            self.initProfile = TRUE

            self.setArrowCursor()
        
    def onProfilePageNext(self, page, dummy):
        if self.xml.get_widget("profileNameEntry").get_text() == "":
            dlg = ErrorDialog(_("You must choose a name for this profile."), parent=self.mainWin)
            self.xml.get_widget("profileNameEntry").grab_focus()
            return TRUE
        
        return FALSE


    def onProfilePageBack(self, page, dummy):
        if self.alreadyRegistered:
            self.xml.get_widget("druid").set_page(self.xml.get_widget("loginPage"))
            return TRUE
        
        return FALSE
    

    def onEnableHardwareButtonToggled(self, button):
        self.sendHardware = button.get_active()
        
        if not self.sendHardware:
            self.xml.get_widget("hostnameTag").hide()
            self.xml.get_widget("hostnameLabel").hide()
            self.xml.get_widget("ipTag").hide()
            self.xml.get_widget("ipLabel").hide()
            self.xml.get_widget("cpuTag").hide()
            self.xml.get_widget("cpuLabel").hide()
            self.xml.get_widget("speedTag").hide()
            self.xml.get_widget("speedLabel").hide()
            self.xml.get_widget("ramTag").hide()
            self.xml.get_widget("ramLabel").hide()
            self.xml.get_widget("hwNoteLabel").hide()
        else:
            self.xml.get_widget("hostnameTag").show()
            self.xml.get_widget("hostnameLabel").show()
            self.xml.get_widget("ipTag").show()
            self.xml.get_widget("ipLabel").show()
            self.xml.get_widget("cpuTag").show()
            self.xml.get_widget("cpuLabel").show()
            self.xml.get_widget("speedTag").show()
            self.xml.get_widget("speedLabel").show()
            self.xml.get_widget("ramTag").show()
            self.xml.get_widget("ramLabel").show()
            self.xml.get_widget("hwNoteLabel").show()
                    
    def onAutoUpdateUp2dateButtonToggled(self, button):
        self.autoUp2date = button.get_active()
    
    def onRegPackagePagePrepare(self, page, dummy):
        self.xml.get_widget("RegPackagePage").emit_stop_by_name("prepare")
        self.xml.get_widget("mainWin").set_title(_("Up2date - Package List (registration)"))
        self.sendPackages = self.xml.get_widget("enableRpmButton").get_active()
        
        if not self.initPackages:
            self.setBusyCursor()
            pwin = progress.Progress()
            pwin.setLabel(_("The Registration Wizard is building a list of RPM packages installed on your system.  Please wait."))

            packages = rpmUtils.getInstalledPackageList(progressCallback = pwin.setProgress)
#            packages = rhnreg.buildPackageList(pwin.setProgress)
            pwin.hide()

            for package in packages:
                self.regPackageArea.append_row((package[0], package[1], package[2]),
                                            TRUE, package[0])

            self.initPackages = TRUE
            self.setArrowCursor()

    def onRegPackagePageBack(self, page, dummy):
        return FALSE

    def onEnableRpmButtonToggled(self, button):
        self.sendPackages = button.get_active()

        if not self.sendPackages:
            self.packageArea.set_sensitive(FALSE)
            self.xml.get_widget("packageLabel").set_sensitive(FALSE)
            self.xml.get_widget("packageNoteLabel").hide()
            pass
        else:
            self.packageArea.set_sensitive(TRUE)
            self.xml.get_widget("packageLabel").set_sensitive(TRUE)
            self.xml.get_widget("packageNoteLabel").show()
            pass

    def onSendPageBack(self, page, dummy):
        return FALSE


    def onSendPageNext(self, page, dummy):
        self.setBusyCursor()

        pwin = progress.Progress()
        pwin.setLabel(_("Sending your profile information to Red Hat Network.  Please wait."))
        username = self.xml.get_widget("loginUserEntry").get_text()
        password = self.xml.get_widget("loginPasswordEntry").get_text()
        email = self.xml.get_widget("loginEmailEntry").get_text()
        profileName = self.xml.get_widget("profileNameEntry").get_text()

        other = None
        # self.autoUpdate indicates if we showed the widget or not/the server supports it
        if self.autoUpdate:
            autoUpdate = str(self.xml.get_widget("autoUpdateUp2dateButton").get_active())
            other = {}
            other['autoUpdateUp2date'] = autoUpdate

        # legacy cruft
        orgId = ""
        orgIdPassword = ""
        try:
            rhnreg.registerUser(username, password, email, orgId, orgIdPassword)
        except up2dateErrors.CommunicationError, e:
            pwin.hide()
            self.fatalError(_("Problem registering user name:\n") + e.errmsg)
        except:
            self.setArrowCursor()
            pwin.hide()
            dlg = ErrorDialog(_("Problem registering username."),
                              parent=self.mainWin)
            return TRUE

        pwin.setProgress(1, 5)

        try:
            self.systemId = rhnreg.registerSystem(username, password, profileName, other=other)
        except up2dateErrors.CommunicationError, e:
            pwin.hide()
            self.fatalError(_("Problem registering system:\n") + e.errmsg)
        except up2dateErrors.RhnUuidUniquenessError, e:
            pwin.hide()
            self.fatalError(_("Problem registering system:\n") + e.errmsg)
        except:
            self.setArrowCursor()
            pwin.hide()
            dlg = ErrorDialog(_("Problem registering system."),
                              parent=self.mainWin)
            return TRUE

        pwin.setProgress(2, 5)

        # write the system id out.
        if not rhnreg.writeSystemId(self.systemId):
            self.setArrowCursor()
            pwin.hide()
            dlg = ErrorDialog(_("Problem writing out system id to disk."),
                              parent=self.mainWin)
            return TRUE

        # incorporate the info from the oemInfoFile as well
        self.oemInfo = rhnreg.getOemInfo()

        # dont send if already registered, do send if they have oemInfo
        if ( not self.alreadyRegistered ) or ( len(self.oemInfo) ):
            # send product registration information
            try:
                rhnreg.registerProduct(self.systemId, self.productInfo, self.oemInfo)
            except up2dateErrors.CommunicationError, e:
                pwin.hide()
                self.fatalError(_("Problem registering personal information:\n") + e.errmsg)
            except:
                self.setArrowCursor()
                pwin.hide()
                dlg = ErrorDialog(_("Problem registering personal information"), parent=self.mainWin)
                return TRUE

                
        pwin.setProgress(3, 5)

        # maybe upload hardware profile
        if self.sendHardware:
            try:
                rhnreg.sendHardware(self.systemId, self.hardware)
            except up2dateErrors.CommunicationError, e:
                pwin.hide()
                self.fatalError(_("Problem sending hardware profile:\n") + e.errmsg)
            except:
                self.setArrowCursor()
                pwin.hide()
                dlg = ErrorDialog(_("Problem sending hardware profile."),
                                  parent=self.mainWin)
                return TRUE

        pwin.setProgress(4, 5)
        
        # build up package list if necessary
        if self.sendPackages:
            # interesting...
            getInfo = 0
            if self.cfg['supportsExtendedPackageProfile']:
                getInfo = 1
                
            packageList = rpmUtils.getInstalledPackageList(progressCallback = lambda amount,
                                                           total: gtk.mainiteration(FALSE),
                                                           getInfo=getInfo)
            selection = []
            for row in range(self.regPackageArea.n_rows):
                rowData = self.regPackageArea.get_row_data(row)
                if rowData[0] == 1:
                    selection.append(rowData[1])
                    
            selectedPackages = []
            for pkg in packageList:
                if pkg[0] in selection:
                    selectedPackages.append(pkg)
            try:
                rhnreg.sendPackages(self.systemId, selectedPackages)
            except up2dateErrors.CommunicationError, e:
                pwin.hide()
                self.fatalError(_("Problem sending packages:\n") + e.errmsg)
            except:
                self.setArrowCursor()
                pwin.hide()
                dlg = ErrorDialog(_("Problem sending packages."),
                                  parent=self.mainWin)
                return TRUE

        pwin.setProgress(5, 5)
        pwin.hide()

        rhnreg.startRhnsd()

        try:
            up2dateAuth.updateLoginInfo()
        except xmlrpclib.Fault, f:
            #print f.faultString
            self.fatalError(f.faultString,wrap=0)
            sys.exit(1)


        rhnChannel.selected_channels = None
        self.setArrowCursor()

        if self.cfg['supportsFinishMessage']:
            self.druid.set_page(self.xml.get_widget("regFinishPage"))
            return TRUE
        else:
            self.druid.set_page(self.xml.get_widget("channelsPage"))
            return True
        
        self.setArrowCursor()
        return FALSE

    def onRegFinishPagePrepare(self, page, dummy):
        self.xml.get_widget("regFinishPage").emit_stop_by_name("prepare")
        self.xml.get_widget("mainWin").set_title(_("Up2date - Registration Information"))
        ret = rhnreg.finishMessage(self.systemId)
        (returnCode, titleText, messageText) = ret[:3]

        textArea = self.xml.get_widget("regFinishTextView")
        page = self.xml.get_widget("regFinishPage")

        page.set_title(titleText)
        if returnCode == 1:
            buffer = gtk.TextBuffer(None)
            buffer.set_text(messageText)
            textArea.set_buffer(buffer)
        if returnCode == -1:
            buffer = gtk.TextBuffer(None)
            buffer.set_text(messageText)
            textArea.set_buffer(buffer)
            # figure out what the heck these mean
            # but make it so they cant click "forward"
            self.druid.set_buttons_sensitive(TRUE, FALSE, TRUE, FALSE)

        # may need to do this on the Next of the preivous page
        if returnCode == 0:
            self.druid.set_page(self.xml.get_widget("channelsPage"))
            return TRUE
                               


    def setupChannelList(self):
        self.currentRow = -1
        window = self.xml.get_widget("channelWindow")
        
        self.channelArea = checklist.CheckList(2)
        self.channelArea.set_column_title(1, _("Description"))
        self.channelArea.set_column_min_width(1,200)
        self.channelArea.set_column_title(2, _("Channel"))
        self.channelArea.column_titles_show()
        #self.channelArea.focus_row = -1

        self.channelArea.connect("select_row", self.showChannelInfo,
                                 (self.xml.get_widget("channelInfoTextArea")))

        window.add(self.channelArea)


    def setupRegPackageList(self):
        window = self.xml.get_widget("regPackageWindow")
        self.regPackageArea = checklist.CheckList(3)
        self.regPackageArea.set_column_title(1, _("Package Name"))
        self.regPackageArea.set_column_min_width(1, 200)
        self.regPackageArea.set_column_title(2, _("Version"))
        self.regPackageArea.set_column_title(3, _("Release"))
        self.regPackageArea.column_titles_show()
        #self.packageArea.connect("select_row", self.showPackageInfo)
        window.add(self.regPackageArea)
        window.show_all()

    def setupPackageList(self):
        self.currentRow = -1
        window = self.xml.get_widget("packageWindow")
        
        self.packageArea = checklist.CheckList(6)
        self.packageArea.set_column_title(1, _("Package Name"))
        #self.packageArea.set_column_max_width(1, 200)
        self.packageArea.set_column_title(2, _("Version"))
        self.packageArea.set_column_min_width(2, 80)
        self.packageArea.set_column_title(3, _("Old Version"))
        self.packageArea.set_column_min_width(3, 80)
        self.packageArea.set_column_title(4, _("Arch"))
        self.packageArea.set_column_min_width(4, 50)
        self.packageArea.set_column_title(5, _("Size"))
        self.packageArea.set_column_min_width(5, 50)
        self.packageArea.set_column_title(6, _("Channel"))
        self.packageArea.set_column_min_width(5, 50)


        self.packageArea.column_titles_show()
        self.packageArea.set_toggled_func(self.updateSelectedSize)

        self.packageArea.connect("select_row", self.showPackageInfo,
                                 (self.xml.get_widget("packageInfoTextArea")))
        window.add(self.packageArea)


        self.xml.get_widget("selectAllButton").connect("toggled",
                                                       self.selectAll)

        self.xml.get_widget("advisoryButton2").connect("clicked",
                                                       self.showAdvisory,
                                                       self.packageArea)


    def setupAvailablePackageList(self):
        self.currentRow = -1
        window = self.xml.get_widget("availablePackageWindow")
                                          
        self.availablePackageArea = checklist.CheckList(6)
        self.availablePackageArea.set_column_title(1, _("Package Name"))
        #self.packageArea.set_column_max_width(1, 200)
        self.availablePackageArea.set_column_title(2, _("Version"))
        self.availablePackageArea.set_column_min_width(2, 50)
        self.availablePackageArea.set_column_title(3, _("Release"))
        self.availablePackageArea.set_column_min_width(3, 50)
        self.availablePackageArea.set_column_title(4, _("Arch"))
        self.availablePackageArea.set_column_min_width(4, 50)
        self.availablePackageArea.set_column_title(5, _("Size"))
        self.availablePackageArea.set_column_min_width(5, 25)
        self.availablePackageArea.set_column_title(6, _("Channel"))
        self.availablePackageArea.set_column_min_width(6, 75)
        self.availablePackageArea.column_titles_show()
        self.availablePackageArea.set_toggled_func(self.updateAvailableSelectedSize)

        self.availablePackageArea.connect("select_row", self.showPackageInfo,
                                         (self.xml.get_widget("availablePackageInfoTextArea")))

        window.add(self.availablePackageArea)

#    def showAvailablePackageInfo(self, *args, **kwargs):
#    def showAvailablePackageInfo(self, area, row, column, event, textarea):
#        self.currentRow = row
#        rowData = area.get_row_data(row)
        
        
        

    def showAdvisory(self, button, area):
        if self.currentRow == -1:
            dlg = OkDialog(_("No package selected. Please select a package first."),
                           self.mainWin)
            return

        self.setBusyCursor()

        rowData = area.get_row_data(self.currentRow)
        advisories = rhnErrata.getAdvisoryInfo(rowData[1])
        self.setArrowCursor()
        if not advisories:
            dlg = OkDialog(_("No advisory information available."),
                           self.mainWin)
            return

        for a in advisories:
            txt = "%s [%s]\n%s\n--------\n%s" % (a['errata_type'],
                                   a['advisory'],
                                   a['topic'],
                                   a['description'])
            #FIXME: make this work
#            dlg = GnomeTextDialog(wrap_text(txt))
#            dlg = MessageWindow(_("up2date advisories"), wrap_text(txt), type="ok", self.mainWin)
            dlg = OkDialog(wrap_text(txt), self.mainWin)
#            dlg.run_and_close()           
            

    def selectAll(self, button):
        if button.get_name() == "selectAllButton":
            area = self.packageArea
        elif button.get_name() == "skippedSelectAllButton":
            area = self.skippedArea
        else:
            return
        for index in range(area.n_rows):
            rowData = area.get_row_data(index)
            if rowData[0] != button.get_active():
                area._toggle_row(index)


    def showPackageInfo(self, area, row, column, event, textarea):
        self.currentRow = row
        rowData = area.get_row_data(row)
        hdr = up2date.getHeader(rowData[1],lite=1)
        buffer = gtk.TextBuffer(None)
        labeltext = hdr['summary'] + "\n" + hdr['description']
        buffer.set_text(labeltext)
        textarea.set_buffer(buffer)

    def showChannelInfo(self, area, row, column, event, textarea):
        # FIXME? rpc to get extended channel info?
        (row,data) = area.get_row_data(row)
        try:
            labeltext = data['description']
            if labeltext == '':
                labeltext = data['name']
        except IndexError:
            labeltext = ""

        buffer = gtk.TextBuffer(None)
        buffer.set_text(labeltext)
        #textarea.backward_delete(textarea.get_length())
        textarea.set_buffer(buffer)

    def __refreshCallback(self):
        while gtk.events_pending():
                gtk.mainiteration(FALSE)


    def onStartPageNext(self,page,dummy):
        # dont show registration for folks not using Red Hat Network
        if not self.cfg['useRhn']:
            self.druid.set_page(self.xml.get_widget("channelsPage"))
        else:
            if rhnreg.registered() and not forceRegister:
                self.druid.set_page(self.xml.get_widget("channelsPage"))
            else:
               self.druid.set_page(self.xml.get_widget("privacyPage"))
 
        return TRUE

    def writeStateFile(self):
#        print "writeStateFile"
        # stash a file in /var/spool/up2date indicating that we
        # want to skip over the first screen or two and go back
        # to where we stopped.
        fd = open("%s/gui.state" % self.cfg['storageDir'], "w+")
        fd.close()

        self.savePackageStateFile()


    def savePackageStateFile(self):
        # stash a copy of all the files we plan to upload
        # so we dont have to comput it again
        infostring = xmlrpclib.dumps((self.storePkgList, ""))
        fd = open("%s/gui.pkgList" % self.cfg['storageDir'] , "w+")
        fd.write(infostring)
        fd.close()
        infostring = xmlrpclib.dumps((self.storeSkipPkgList, ""))
        fd = open("%s/gui.skipPkgList" % self.cfg['storageDir'], "w+")
        fd.write(infostring)
        fd.close()

    def openPackageStateFile(self):
        if os.stat("%s/gui.pkgList" % self.cfg['storageDir'])[6] == 0:
            self.pkgList = []
        else:
            fd = open("%s/gui.pkgList" % self.cfg['storageDir'], "r")
            info = fd.read()
            tmp_args, tmp_methods = xmlrpclib.loads(info)
            self.pkgList = tmp_args[0]

        if os.stat("%s/gui.skipPkgList" % self.cfg['storageDir'])[6] == 0:
            self.skipPkgList = []
        else:
            fd = open("%s/gui.skipPkgList" %self.cfg['storageDir'], "r")
            info = fd.read()
            tmp_args, tmp_methods = xmlrpclib.loads(info)
            self.skipPkgList = tmp_args[0]
        

    def deleteStateFile(self):
        try:
            os.unlink("%s/gui.state" % self.cfg['storageDir'])
            os.unlink("%s/gui.pkgList" % self.cfg['storageDir'])
            os.unlink("%s/gui.skipPkgList" % self.cfg['storageDir'])
        except OSError:
            print "state files not found"
            

    def detectStateFile(self):
        if os.access("%s/gui.state" % self.cfg['storageDir'], os.R_OK):
            return 1
        return 0

    def __preparePackageList(self):
#        cfg["headerFetchCount"] = 20
        # so we can get self.Plist.installedPackageHash()
        self.pList = packageList.PackageList()
        self.pList.run()

        self.installedPackages = self.pList.getInstalledPackages()

    def onChannelsPageNext(self, page, dummy):
        
        #self.updateChannelSubscriptions()

        # invalidate the packae list cache
        # this forces up2date ot recaculate the available package list

        # FIXME: this is probabaly not valid anymore
        up2date.avail_package_list = []
        rhnChannel.channel_blacklist = []    
        blacklist_updated = None
        
        # tell it which channels to ignore
        for index in range(self.channelArea.n_rows):
            rowData = self.channelArea.get_row_data(index)
            if rowData[0] == 0:
                rhnChannel.channel_blacklist.append(rowData[1]['label'])
                # so we know to recreate the avail package lists. A little
                # wasteful, but correct. 
                blacklist_updated = TRUE

        if not self.gotPackages or blacklist_updated:
#            self.pkgList = []
#            self.selectedPkgList = []
#            self.skipPkgList = []
            
            self.totalSelectedSize = long(0)
            self.druid.set_buttons_sensitive(TRUE, FALSE, TRUE, TRUE)
            
            pwin = progress.Progress()
            pwin.setLabel(_("Red Hat Update Agent is building a list of updated\nRPM packages installed on your system.  Please wait."))

            try:
                if self.cfg['useRhn']:
                    up2dateAuth.maybeUpdateVersion()
                # override whatever this value is so we get good
                # interactive GUI response
                self.cfg["headerFetchCount"] = 20
                # so we can get self.Plist.installedPackageHash()
                self.pList = packageList.PackageList()
                self.pList.msgCallback = pwin.setLabel
                self.pList.progressCallback = pwin.setProgress
                self.pList.ignoreMsgCallback = None
                self.pList.addForcePackages([])
                self.pList.run()

                # FIXME: insert code to handle possible up2date updates here?
                self.pkgList = self.pList.getPackagesToInstall()

                self.skipPkgList = self.pList.getSkippedPackages()
                # look to see if up2date is in the list of packages to update
                self.storePkgList = self.pkgList


               # handy to have when we want to display what package were replacing
                self.installedPackages = self.pList.getInstalledPackages()
                
                if self.pkgList:
                    tmpPkgNames = map(lambda a:a[0], self.pkgList)
                    if "up2date" in tmpPkgNames and self.cfg["updateUp2date"]:
                        for pkg in self.pkgList:
                            if pkg[0] == "up2date":
                                channelName = pkg[6]
                                channel = rhnChannel.selected_channels.getByName(channelName)
                                if channel['type'] == 'up2date':
                                
                                    self.storePkgList = self.pkgList
                                    self.storeSkipPkgList = self.skipPkgList
                                    self.tmpPkgList = []
                                    self.tmpPkgList.append(pkg)

                                    dlg = QuestionDialog(_("There is a new version of up2date available. Install the new version and restart?"))
                                    if dlg.getrc():
                                        # cant write state here, need to trim these files first
                                        #self.writeStateFile()
                                        self.pkgList = self.tmpPkgList
                                        self.tmpSkipPkgList = self.skipPkgList
                                        self.skipPkgList = []
                                        self.updateUp2date = 1
                

            except up2dateErrors.RpmError, e:
                pwin.destroy()
                self.fatalError(_("There was a fatal RPM error.  The message was:\n") + e.errmsg)
            except up2dateErrors.FileNotFoundError, e:
                pwin.destroy()
                self.fatalError(_("There was a fatal error communicating with the server.  The message was:\n") + e.errmsg)
            except up2dateErrors.CommunicationError, e:
                pwin.destroy()
                self.fatalError(_("There was a fatal error communicating with the server.  The message was:\n") + e.errmsg)
            except OSError, e:
                self.fatalError(_("An unexpected OS error occurred:\n%s") % e)

            pwin.destroy()
            while gtk.events_pending():
                gtk.mainiteration(FALSE)

            self.gotPackages = TRUE

        if len(self.skipPkgList) > 0:
            self.druid.set_page(self.xml.get_widget("skippedPage"))
        else:
            self.druid.set_page(self.xml.get_widget("packagePage"))
            
        return TRUE

    def onSkippedPagePrepare(self, page, dummy):
        self.xml.get_widget("skippedPage").emit_stop_by_name("prepare")
        self.xml.get_widget("mainWin").set_title(_("Up2date - Skipped Packages"))
        if not self.installedPackages:
            self.__preparePackageList()

        if not self.gotSkippedPackages:
            self.skippedArea.freeze()
            for pkg,reason in self.skipPkgList:
                try:
                    self.skippedArea.append_row((pkg[0],
                                                 "%s-%s" % (pkg[1],pkg[2]),
                                                 self.getOldPackageString(pkg[0]),
                                                 pkg[4],
                                                 "%d kB" % (int(pkg[5]) / 1024),
                                                 reason), FALSE, pkg)
                except up2dateErrors.RpmError, e:
                    dlg = WarningDialog(e.errmsg, self.mainWin)
                    
            # get max num of chars and assuming a char size of roughly 8 pixels
            maxlength = max(map(lambda x: len(x[0][0]), self.skipPkgList)) * 8
            # smallest column width=100, largest=200, but will try to fit to
            # length of largest packagename.
            self.skippedArea.set_column_min_width(1, max(min(maxlength, 200), 100))
            self.skippedArea.thaw()

            self.gotSkippedPackages = TRUE
        self.druid.set_buttons_sensitive(TRUE, TRUE, TRUE, TRUE)

    def onSkippedPageNext(self, page, dummy):
        pass

    def onChannelsPagePrepare(self,page, dummy):
        self.xml.get_widget("channelsPage").emit_stop_by_name("prepare")
        self.xml.get_widget("mainWin").set_title(_("Up2date - Channels"))
        self.druid.set_buttons_sensitive(FALSE, TRUE, TRUE, TRUE)
        descriptionLabel = self.xml.get_widget("SubChannelDescriptionLabel")

        if self.channelArea.n_rows:
            return

        # we need to see if the system is 
        try:
            channels = rhnChannel.getChannelDetails()
        except xmlrpclib.Fault, f:
            dlg = ErrorDialog(f.faultString, parent=self.mainWin)
            # if we need to go to the website to assign entitlements,
            # exit here
            if abs(f.faultCode) == 31:
                sys.exit()
            return TRUE
        except up2dateErrors.CommunicationError, e:
            dlg = ErrorDialog(
                _("There was a communication error with the server: %s") %
                e.errmsg, parent=self.mainWin)
            sys.exit(1)
        except up2dateErrors.NoChannelsError, e:
            dlg = ErrorDialog(e.errmsg, parent=self.mainWin)
            sys.exit(1)
            
        

        self.channelArea.freeze()
        row = 0
        for channel in channels:
            values = []
            values.append(channel['name'])
            values.append(channel['label'])
            values.append(channel['description'])
            # kluge to store the initial status of the channel so
            # we know what channels to sub/unsub
            channel['initial_status'] = TRUE
            textlist =  tuple(values[:4])
            self.channelArea.append_row(textlist, TRUE, channel)
                                          
        if channels:
            self.channelArea.select_row(0,0)
            
        self.channelArea.thaw()
        
    # If you have two versions of the same package installed, this function
    # will always pick the higher version to return.
    def getOldPackageString(self, pkgName):
        if not self.installedPackages:
            self.__preparePackageList()
            
        pkg = self.installedPackages.get(pkgName)
        if not pkg:
            return ""
       
        highString = ""
        for currPkg in pkg:
            pkgString = "%s-%s" % (currPkg[1], currPkg[2])
            if (not highString or highString < pkgString):
                highString = pkgString
        
        #print highString
        return highString
    
    def onPackagePagePrepare(self, page, dummy):
        self.xml.get_widget("packagePage").emit_stop_by_name("prepare")
        self.xml.get_widget("mainWin").set_title(_("Up2date - Package List"))
        self.packageArea.freeze()
        self.packageArea.clear()
        self.totalSelectedSize = long(0)


        #FIXME: we need a hash of the installed package names -> the latest version installed
        #       we will use this to populate the "old version" info in the gui
        #       it might also be useful if we had a data structure clearly indicating what
        #       old package was replaced by what new package (including obsoletes...) that
        #       probabaly the best, since it may be useful to report that exact info at some point
        if len(self.skipPkgList) > 0:
            for index in range(self.skippedArea.n_rows):
                rowData = self.skippedArea.get_row_data(index)
                if rowData[0] == 1:
                    pkg = rowData[1]
                    self.packageArea.append_row((pkg[0],
                                                 "%s-%s" % (pkg[1], pkg[2]),
                                                 self.getOldPackageString(pkg[0]),
                                                 pkg[4],
                                                 "%d kB" % (int(pkg[5]) / 1024), pkg[6]),
                                                TRUE, pkg)
                    try:
                        if not up2date.isPackageCached(pkg):
                            self.totalSelectedSize = self.totalSelectedSize + int(pkg[5])
                        self.pkgsSelected = TRUE
                    except up2dateErrors.RpmError, e:
                        self.fatalError(_("There was a fatal RPM error. The message was:\n") + e.errmsg)
        elif len(self.pkgList) == 0:

            dlg = OkDialog(_("Your system is fully updated.  No new packages are needed."), self.mainWin)
#            dlg.run_and_close()
            sys.exit(0)
            
        for pkg in self.pkgList:
            try:
                selected = 0
                self.packageArea.append_row((pkg[0],
                                             "%s-%s" % (pkg[1], pkg[2]),
                                             self.getOldPackageString(pkg[0]),
                                             pkg[4], 
                                             "%d kB" % (int(pkg[5]) / 1024), pkg[6]),
                                            selected, pkg)
            except up2dateErrors.RpmError, e:
                dlg = WarningDialog(e.errmsg, self.mainWin)


                

        # get max num of chars and assuming a char size of roughly 8 pixels.
        if len(self.pkgList):
            maxlength = max(map(lambda x: len(x[0]), self.pkgList)) * 8
        else:
            # 150 is just halfway between the min of 100 pixels and the max of 200 
            maxlength = 150
            
        # smallest column width=100, largest=200, but will try to fit to length
        # of largest packagename.
        self.packageArea.set_column_min_width(1, max(min(maxlength, 200), 100))
        self.xml.get_widget("sizeLabel").set_text("%d kB" % (self.totalSelectedSize / 1024))
        self.packageArea.thaw()


# FIXME: make work
#        if self.updateUp2date:
#            area = self.packageArea
#            for index in range(area.n_rows):
#                rowData = area.get_row_data(index)
#                self.updateAvailableSelectedSize(TRUE, rowData[1])

        if self.pkgsSelected or self.cfg["showAvailablePackages"]:
            self.druid.set_buttons_sensitive(TRUE, TRUE, TRUE, TRUE)
        else:
            self.druid.set_buttons_sensitive(TRUE, FALSE, TRUE, TRUE)

    def __packagePageDryRun(self):
        pwin = progress.Progress()

        while gtk.events_pending():
            gtk.mainiteration(FALSE)
        try:
            (self.depPackages,self.placehold) = up2date.dryRun(self.selectedPkgList,
                                                               pwin.setLabel,
                                                               pwin.setProgress,
                                                               self.__refreshCallback)
        except up2dateErrors.CommunicationError, e:
            pwin.destroy()
            self.fatalError(_("There was a fatal error communicating with the server.  The message was:\n") + e.errmsg)
        except up2dateErrors.RpmError, e:
            pwin.destroy()
            dlg = self.fatalError(
                _("There was an RPM error.  The message was:\n") + e.errmsg
                )
        except up2dateErrors.RpmInstallError, e:
            pwin.destroy()
            dlg = self.fatalError(_("There was an RPM install error. The message was:\n") + e.errmsg)
        except up2dateErrors.DependencyError, e:
            pwin.destroy()
            dlg = WarningDialog(_("There was a package dependency problem.  The message was:\n") + \
                                e.errmsg + \
                                _("\nPlease modify your package selections and try again."),
                                self.mainWin)
            return TRUE
        except up2dateErrors.DependencySenseError, e:
            pwin.destroy()
            errmsg = "There was a dependency sense error with the sense: %s" % e.sense
            dlg = WarningDialog(wrap_text(errmsg), self.mainWin)
            return TRUE
        except up2dateErrors.ConflictError, e:
            pwin.destroy()
            dlg = WarningDialog(wrap_text(e.errmsg), self.mainWin)
            return TRUE
        except up2dateErrors.FileNotFoundError, e:
            pwin.destroy()
            dlg = WarningDialog(wrap_text(e.errmsg), self.mainWin)
            return TRUE  
        
        pwin.destroy()
        while gtk.events_pending():
            gtk.mainiteration(FALSE)

    def __showRequirePackageDialog(self):
        dlg = ErrorDialog(_("""You must select at least one package.
If you do not wish to update any packages,
press the "Cancel" button to exit Update Agent."""),
                          parent = self.mainWin)

    def onPackagePageNext(self, page, dummy):
        def cb(foo):
            return foo

        if self.totalSelectedSize > up2dateUtils.freeDiskSpace():
            dlg = ErrorDialog(_("""The total size of selected packages is %d kB, but
You only have %d kB of free space.
Please unselect some packages and continue.""") % (self.totalSelectedSize / 1024,
                                                   up2dateUtils.freeDiskSpace() / 1024),
                              self.mainWin)
                                            
            return TRUE

        if not self.pkgsSelected and not self.cfg["showAvailablePackages"]:
            self.__showRequirePackageDialog()
            return TRUE

        # build list of selected packages
        rowData = ()
        self.selectedPkgList = []
        newPackages = []
        for index in range(self.packageArea.n_rows):
            rowData = self.packageArea.get_row_data(index)
            if rowData[0] == 1:
                self.selectedPkgList.append(rowData[1])

        # go ahead and run this now if were not going to
        # the available package screens
        if not self.cfg["showAvailablePackages"]:
            ret = self.__packagePageDryRun()
            if ret:
                return ret
                
        if self.cfg["showAvailablePackages"]:
            self.druid.set_page(self.xml.get_widget("availablePackagePage"))
            return TRUE
        
        if len(self.depPackages) > 0:
            self.druid.set_page(self.xml.get_widget("dependencyPage"))
            return TRUE
        else:
            self.druid.set_page(self.xml.get_widget("retrievalPage"))
            return TRUE


    def onPackagePageBack(self, page, dummy):
        if len(self.skipPkgList) > 0:
            self.druid.set_page(self.xml.get_widget("skippedPage"))
        else:
            self.druid.set_page(self.xml.get_widget("startPage"))
        return TRUE


    
    def onAvailablePackagePagePrepare(self, page, dummy):
        self.xml.get_widget("availablePackagePage").emit_stop_by_name("prepare")
        self.xml.get_widget("mainWin").set_title(_("Up2date - Available Packages"))
        self.availablePackageArea.freeze()
        self.availablePackageArea.clear()

        availPkgList = up2date.computeAvailablePackages()
        
        for pkg in availPkgList:
            try:
                self.availablePackageArea.append_row((pkg[0], pkg[1], pkg[2], pkg[4],
                                             "%d kB" % (int(pkg[5]) / 1024), pkg[6]),FALSE, pkg)
            except up2dateErrors.RpmError, e:
                dlg = WarningDialog(e.errmsg, self.mainWin)

        # get max num of chars and assuming a char size of roughly 8 pixels.
        if len(availPkgList):
            maxlength = max(map(lambda x: len(x[0]), self.pkgList)) * 8
        else:
            # 150 is just halfway between the min of 100 pixels and the max of 200 
            maxlength = 150
            
        # smallest column width=100, largest=200, but will try to fit to length
        # of largest packagename.
        self.availablePackageArea.set_column_min_width(1, max(min(maxlength, 200), 100))
        self.xml.get_widget("availableSizeLabel").set_text("%d kB" % (self.totalSelectedSize / 1024))
        self.availablePackageArea.thaw()

        if self.pkgsSelected:
            self.druid.set_buttons_sensitive(TRUE, TRUE, TRUE, TRUE)
        else:
            self.druid.set_buttons_sensitive(TRUE, FALSE, TRUE, TRUE)

        return TRUE

    def onAvailablePackagePageNext(self, page, dummy):
        
        if self.totalSelectedSize > up2dateUtils.freeDiskSpace():
            dlg = ErrorDialog(_("""The total size of selected packages is %d kB, but
You only have %d kB of free space.
Please unselect some packages and continue.""") % (self.totalSelectedSize / 1024,
                                                   up2dateUtils.freeDiskSpace() / 1024),
                              self.mainWin)
                                            
            return TRUE

        if not self.pkgsSelected:
            self.__showRequirePackageDialog()
            return TRUE
        # build list of selected packages
        
        rowData = ()
        newPackages = []
        for index in range(self.availablePackageArea.n_rows):
            rowData = self.availablePackageArea.get_row_data(index)
            if rowData[0] == 1:
                self.selectedPkgList.append(rowData[1])

        ret = self.__packagePageDryRun()
        if ret:
            return ret
        
        if len(self.depPackages) > 0:
            self.druid.set_page(self.xml.get_widget("dependencyPage"))
            return TRUE
        else:
            self.druid.set_page(self.xml.get_widget("retrievalPage"))
            return TRUE
        
        return TRUE

    def onDependencyPageBack(self, page, dummy):
        if self.cfg["showAvailablePackages"]:
            self.druid.set_page(self.xml.get_widget("availablePackagePage"))
        else:
            self.druid.set_page(self.xml.get_widget("packagePage"))
        return TRUE
        
        
    def onDependencyPagePrepare(self, page, dummy):
        self.xml.get_widget("dependencyPage").emit_stop_by_name("prepare")
        self.xml.get_widget("mainWin").set_title(_("Up2date - Dependencies"))
        area1 = self.xml.get_widget("dependencyArea1")
        area1.clear()
        for pkg in self.depPackages:
            area1.append(pkg)
            # dont add to total size if we already have it downloaded
            if not up2date.isPackageCached(pkg):
                self.totalSelectedSize = self.totalSelectedSize + int(pkg[5])
            self.pkgsSelected = TRUE

        if self.totalSelectedSize > up2dateUtils.freeDiskSpace():
            dlg = ErrorDialog(_("""The total size of selected packages is %d kB, but
You only have %d kB of free space.
Please unselect some packages and continue.""") % (self.totalSelectedSize / 1024,
                                                   up2dateUtils.freeDiskSpace() / 1024),
                                            self.mainWin)
            self.druid.set_page(self.xml.get_widget("packagePage"))
	    return TRUE


    def setRetrievalProgress(self, amount, total, speed = 0, secs = 0):
        if total:
            i = float(amount) / total
        else:
            i = 1
            
        self.progress.set_fraction(i)

        if speed:
            trans_bps_str = "%d of %d kB transferred at %d kB/sec\n" % \
                            (amount/1024, total/1024, speed/1024)
            totalTime = total / speed
            trans_time_str = "Package transfer time: %02d:%02d:%02d" % \
                             (totalTime / 3600, (totalTime % 3600) / 60,
                              totalTime % 60)
            trans_rem_str = " (%02d:%02d:%02d remaining)" % \
                            (secs / 3600, (secs % 3600) / 60,
                             (secs % 60))
            tstr = trans_bps_str + trans_time_str + trans_rem_str
        else:
            tstr = _("Package already downloaded")

        self.xml.get_widget("timeLabel").set_text(tstr)
        
        while (gtk.events_pending()):
            gtk.mainiteration(FALSE)

    def startRetrievalTimer(self):
        pass

    def labelcb(self, name, shortName=""):
        label = self.xml.get_widget("retrievePackageNameLabel")
        label.set_text(name)
            

    def doRetrieval(self):

        def cb(arg):
            return arg

        gtk.threads_enter()
        self.progress = self.xml.get_widget("retrievePackageProgress")
        totalProgress = self.xml.get_widget("retrieveTotalProgress")
        totalProgress.set_fraction(0)
        

        self.setBusyCursor()
        
        pkgCount = len(self.selectedPkgList)
        totalRetrievedSize = 0

        # since we dont want to download any packages
        # just set the count to 0, so we dont have to
        # further nest this mess
        if self.cfg["noDownload"]:
            pkgCount = 0
            
        for index in range(pkgCount):
            self.startRetrievalTimer()
            hdr = up2date.getHeader(self.selectedPkgList[index],lite=1)
            self.xml.get_widget("retrieveInfoLabel").set_text("%s\n%s" %
                                                              (hdr['summary'],
                                                              hdr['description']))
            try:
                up2date.getPackage(self.selectedPkgList[index],
                                   self.labelcb,
                                   self.setRetrievalProgress)
            except up2dateErrors.CommunicationError, e:
                self.fatalError(_("Error while retrieving package %s.\nThe message was:\n%s") % (up2dateUtils.pkgToString(self.selectedPkgList[index]), e.errmsg))
            except up2dateErrors.FileNotFoundError, e:
                self.fatalError(_("There was a fatal error communicating with the server.  The message was:\n") + e.errmsg)
            
            # do signature checking only if GPG installation checks out,
            # and GPG checking is enabled.
            # we already warned them about any errors when we started up.
            if self.cfg["useGPG"] and not gpgUtils.checkGPGInstallation():
                try:
                    res = up2date.hasBadSignature(self.selectedPkgList[index])
                except up2dateErrors.RpmError, e:
                    self.fatalError(_("A fatal RPM error has occurred.  The message was:\n%s") % e.errmsg)
                if res == 1:
                    dlg = QuestionDialog(_("The package %s is not signed with a GPG signature.  Continue?")
                                         % up2dateUtils.pkgToString(self.selectedPkgList[index]))
                    if not dlg.getrc():
                        sys.exit(1)
                if res == 2:
                    dlg = QuestionDialog(_("The package %s does not have a valid GPG signature.\nIt has been tampered with or corrupted.  Continue?") %
                                         up2dateUtils.pkgToString(self.selectedPkgList[index]))
                    if not dlg.getrc():
                        sys.exit(1)

                if res == 3:
                    dlg = QuestionDialog(_("The package %s is signed with an untrusted GPG signature.  Continue?") %
                                         up2dateUtils.pkgToString(self.selectedPkgList[index]))
                    if not dlg.getrc():
                        sys.exit(1)

                if res == 4:
                    dlg = QuestionDialog(_("The package %s is signed with an unknown GPG signature. Continue?") %
                                         up2dateUtils.pkgToString(self.selectedPkgList[index]))
                    if not dlg.getrc():
                        sys.exit(1)

            totalRetrievedSize = totalRetrievedSize + \
                                 int(self.selectedPkgList[index][5])

            if self.totalSelectedSize:
                i = float(totalRetrievedSize) / self.totalSelectedSize
            else:
                i = 1
            # shouldnt happen, but just in case
            if i > 1.0:
                i = 1.0
            if i < 0:
                i = 0
                
            totalProgress.set_fraction(i)
            while gtk.events_pending():
                gtk.mainiteration(FALSE)

        self.xml.get_widget("packagesFinishedLabel").set_text(_("All finished.  Click \"Forward\" to continue."))
        self.druid.set_buttons_sensitive(TRUE, TRUE, TRUE, TRUE)
        # XXX remove me when locking is fixed in gtk
        self.setArrowCursor()
        gtk.threads_leave()
        return 0

    def trimPackageLists(self):
        # remove up2date and any of it's deps from the package lists we save
        for pkg in self.selectedPkgList:
            if pkg in self.storePkgList:
                del self.storePkgList[self.storePkgList.index(pkg)]
            if pkg in self.storeSkipPkgList:
                del self.storeSkipPkgList[self.storeSkipPkgList.index(pkg)]


    def onRetrievalPagePrepare(self, page, dummy):
        self.xml.get_widget("retrievalPage").emit_stop_by_name("prepare")
        self.xml.get_widget("mainWin").set_title(_("Up2date - Package Retrieval"))
        #                                       back   cacel forwardd
        self.druid.set_buttons_sensitive(FALSE, FALSE, TRUE, FALSE)

        if self.updateUp2date:
            self.trimPackageLists()

        while gtk.events_pending():
            gtk.mainiteration(FALSE)

        # total hack to get this function to start as soon as this
        # on exits.  GTK makes me do ugly things.
        gtk.timeout_add(0, self.doRetrieval)


    def onRetrievalPageNext(self, page, dummy):
        if self.cfg["retrieveOnly"]:
            self.druid.set_page(self.xml.get_widget("finishPage"))
        else:
            self.druid.set_page(self.xml.get_widget("installPage"))
        return TRUE

    def onRetrievalPageBack(self, page, dummy):
        self.xml.get_widget("packagesFinishedLabel").set_text("...")
        self.druid.set_page(self.xml.get_widget("packagePage"))
        return TRUE
    

    def rpmCallback(self, what, amount, total, hdr, path):
        #print "what: %s amount: %s total: %s hdr: %s path: %s" % (what, amount, total, hdr, path)
        if what == rpm.RPMCALLBACK_INST_OPEN_FILE:
            fileName = "%s/%s-%s-%s.%s.rpm" % (path,
                                               hdr['name'],
                                               hdr['version'],
                                               hdr['release'],
                                               hdr['arch'])
            try:
                self.fd = os.open(fileName, os.O_RDONLY)
            except:
                raise up2dateErrors.RpmError(_("Error opening %s") % fileName)
            
            return self.fd
        
        elif what == rpm.RPMCALLBACK_INST_START:
            # on rollbacks, hdr == None
            if type(hdr) == type(""):
                #repacking a rpm
                self.installLabel.set_text(_("Repackaging..."))
                self.pkgLabel.set_text(hdr)
            elif hdr:
                fileName = "%s/%s-%s-%s.%s.rpm" % (path,
                                                   hdr['name'],
                                                   hdr['version'],
                                                   hdr['release'],
                                                   hdr['arch'])
                self.pkgIndex = self.pkgIndex + 1
                self.installLabel.set_text(_("Installing..."))
                self.pkgLabel.set_text(fileName)
                
        elif what == rpm.RPMCALLBACK_REPACKAGE_PROGRESS:
#            print "---what: %s amount: %s total: %s hdr: %s path: %s" % (what, amount, total, hdr, path)
            if total == 0:
                i = 0
            else:
                i = (amount + 1.0) / total
            if i > 1:
                i = 1.0
            elif i < 0:
                i = 0
#            print "|||||||| i: %s  ||||||||" % i
            self.totalProgressLabel.set_text(_("Total Progress (repackaging):"))
            self.totalProgress.set_fraction(i)
                
        elif what == rpm.RPMCALLBACK_INST_CLOSE_FILE:
           # print "what: %s amount: %s total: %s hdr: %s path: %s" % (what, amount, total, hdr, path)
            os.close(self.fd)
            # we used to do a up2date.remoteAddPackage() here
            
            i = (self.pkgIndex * 1.0) / self.pkgCount
            if i > 1:
                i = 1.0
            elif i < 0:
                i = 0
            self.totalProgressLabel.set_text(_("Total Progress:"))
            self.totalProgress.set_fraction(i)

        elif what == rpm.RPMCALLBACK_INST_PROGRESS:
            #print "what: %s amount: %s total: %s hdr: %s path: %s" % (what, amount, total, hdr, path)
            # not sure why we get a zero total
            if total == 0:
                i = 0
            else:
                i = (amount + 1.0) / total
            if i > 1:
                i = 1.0
            elif i < 0:
                i = 0
            self.progress.set_fraction(i)

        elif what == rpm.RPMCALLBACK_UNINST_STOP:
            # we used to do a up2date.remoteDelPackage() here
            pass
        
        if (rpm.__dict__.has_key("RPMCALLBACK_UNPACK_ERROR")):
            if ((what == rpm.RPMCALLBACK_UNPACK_ERROR) or
                (what == rpm.RPMCALLBACK_CPIO_ERROR)):
                pkg = "%s-%s-%s" % (hdr[rpm.RPMTAG_NAME],
                                    hdr[rpm.RPMTAG_VERSION],
                                    hdr[rpm.RPMTAG_RELEASE])
                
                if what == rpm.RPMCALLBACK_UNPACK_ERROR:
                    raise up2dateErrors.RpmInstallError, ("There was a rpm unpack error  installing the package: %s" % pkg, pkg)
                elif what == rpm.RPMCALLBACK_CPIO_ERROR:
                    raise up2dateErrors.RpmInstallError, ("There was a cpio error installing the package: %s" % pkg, pkg)

        
        while gtk.events_pending():
            gtk.mainiteration(FALSE)


    def doInstallation(self):
        gtk.threads_enter()
        self.progress = self.xml.get_widget("installPackageProgress")
        self.totalProgress = self.xml.get_widget("installTotalProgress")
        self.totalProgress.set_fraction(0)
        self.pkgLabel = self.xml.get_widget("installPackageNameLabel")
        self.installLabel = self.xml.get_widget("installingLabel")
        self.totalProgressLabel = self.xml.get_widget("totalProgressLabel")
        self.pkgIndex = 0
        self.pkgCount = len(self.selectedPkgList)

        self.setBusyCursor()
        try:
            kernelsToInstall = up2date.installPackages(self.selectedPkgList, self.rpmCallback)
        except up2dateErrors.CommunicationError, e:
            self.setArrowCursor()
            self.fatalError(_("There was a fatal RPM error. The message was:\n") + e.errmsg)
        except up2dateErrors.RpmError, e:
            self.setArrowCursor()
            self.fatalError(_("There was a fatal RPM error.  The message was:\n") + e.errmsg)
        except up2dateErrors.RpmInstallError, e:
            self.setArrowCursor()
            self.fatalError(_("There was a fatal RPM install error. The message was:\n") + e.errmsg)
        except up2dateErrors.TransactionError, e:
            self.setArrowCursor()
            self.fatalError(_("There was a fatal RPM install error. The message was:\n") + e.errmsg)

        
        if len(kernelsToInstall) and lilocfg:
            try:
                up2date.installBootLoader(kernelsToInstall)
            except lilocfg.LiloConfError, e:
                dlg = WarningDialog(e.errmsg, self.mainWin)
            except lilocfg.LiloInstallError, e:
                dlg = WarningDialog(e.errmsg, self.mainWin)
                
        if not self.cfg["keepAfterInstall"]:
            for pkg in self.selectedPkgList:
                try:
                    up2date.removePackage(pkg)
                except up2dateErrors.FileError, e:
                    dlg = WarningDialog(e.errmsg, self.mainWin)

                while gtk.events_pending():
                    gtk.mainiteration(FALSE)

        self.xml.get_widget("installingFinishedLabel").set_text(_("All finished.  Click \"Forward\" to continue."))
        self.druid.set_buttons_sensitive(FALSE, TRUE, TRUE, TRUE)
        # XXX remove me when locking is fixed in gtk
        self.setArrowCursor()
        gtk.threads_leave()
        return 0
    

    def onInstallPagePrepare(self, page, dummy):
        self.xml.get_widget("installPage").emit_stop_by_name("prepare")
        self.xml.get_widget("mainWin").set_title(_("Up2date - Package Installation"))
        self.druid.set_buttons_sensitive(FALSE, FALSE, TRUE, TRUE)
        while gtk.events_pending():
            gtk.mainiteration(FALSE)

        # total hack to get this function to start as soon as this
        # on exits.  GTK makes me do ugly things.
        gtk.timeout_add(0, self.doInstallation)


    def onInstallPageBack(self, page, dummy):
        self.xml.get_widget("installingFinishedLabel").set_text("...")
        self.druid.set_page(self.xml.get_widget("packagePage"))
        return TRUE


    def onFinishPagePrepare(self, page, dummy):
        self.druid.set_buttons_sensitive(FALSE, TRUE, FALSE, TRUE)
        self.xml.get_widget("finishPage").emit_stop_by_name("prepare")
        self.xml.get_widget("mainWin").set_title(_("Up2date - Finish Page"))
        self.xml.get_widget("finishPage").connect ('finish', self.onFinishPageFinish)
        self.druid.set_show_finish(TRUE)
        self.druid.finish.set_label (_("Finish"))
        
        text = _("The Red Hat Update Agent has finished ")
        if self.cfg["retrieveOnly"]:
            text = text + _("retrieving\n the following packages successfully:\n\n")
        else:
            text = text + _("installing\n the following packages successfully:\n\n")

        for pkg in self.selectedPkgList:
            text = text + up2dateUtils.pkgToString(pkg) + "\n"

        if self.cfg["retrieveOnly"]:
            text = text + _("""
Because of your settings, these packages were only downloaded,
not installed.  If you wish to change your settings, please run the
"up2date-config" program.""")

            
        buffer = gtk.TextBuffer(None)
        buffer.set_text(text)
        self.xml.get_widget("finishArea").set_buffer(buffer)

        if self.updateUp2date:
            self.writeStateFile()
            dlg = OkDialog("Up2date will now be restarted")
            up2dateUtils.restartUp2date()
            gtk.mainquit()
            sys.exit()
        return FALSE


    def onFinishPageFinish(self, page, dummy=None):
        gtk.mainquit()
    
    
def rootWarning():
    dlg = ErrorDialog(_("You must run the Update Agent as root."))
#    dlg.run_and_close()

def errorWindow(msg):
    dlg = ErrorDialog(wrap_text(msg))
#    dlg.run_and_close()

def main():
    def cb(foo):
        return foo
        
    test = 0

#    if len(sys.argv) > 0:
#        if sys.argv[0] == "-t" or saveargs[0] == "--test":
#            test = 1
        
    signal.signal(signal.SIGINT, signal.SIG_DFL)

    if os.geteuid() != 0 and not test:
        rootWarning()
        sys.exit(1)

    try:
        from gtk import _disable_gdk_threading
        _disable_gdk_threading()
    except ImportError:
        pass

    gui = Gui()
    gtk.mainloop()

    
if __name__ == "__main__":
    try:
        from rhn import rpclib
    except ImportError:
        rpclib = __import__("xmlrpclib")
        
    try:
        main()
    except rpclib.ResponseError, e:
        print e
    except IOError, e:
        print _("There was some sort of I/O error: %s") % e.errmsg
