# This file is a portion of the Red Hat Network Panel Applet
#
# Copyright (C) 1999-2002 Red Hat, Inc. All Rights Reserved.
# Distributed under GPL version 2.
#
# Author: Chip Turner
#
# def help added by Tammy Fox
#
# $Id: rhn_applet.py,v 1.114 2003/11/09 16:56:33 veillard Exp $

import gnome
import gnome.ui

# from msw to avoid odd bugs in some pygtk builds
try:
    from gtk import _disable_gdk_threading
    _disable_gdk_threading()
except ImportError:
    pass

import gtk
import gtk.gdk

import string
import os
import sys
import math
import traceback
import time
from StringIO import StringIO

import rhn_utils

import rhn_applet_animation
from rhn_applet_model import rhnAppletModelGUI
from rhn_applet_dialogs import \
     rhnAppletNoticeWindow, \
     rhnRegistrationPromptDialog, \
     rhnAppletAboutWindow, \
     rhnAppletFirstTimeDruid, \
     rhnAppletErrorDialog, \
     rhnAppletExceptionDialog

from rhn_utils import \
     rhnAppletException, \
     rhnAppletRPCFault, \
     rhnAppletNetworkException

import rhn_applet_version

import eggtrayicon

import gettext
GETTEXT_DOMAIN = "rhn-applet"
gettext.bindtextdomain (GETTEXT_DOMAIN, "/usr/share/locale")
gettext.textdomain (GETTEXT_DOMAIN)
try:
    gettext.install(GETTEXT_DOMAIN, "/usr/share/locale", 1)
except IOError:
    import __builtin__
    __builtin__.__dict__['_'] = unicode

REFRESH_INTERVAL = 60
NETWORK_RETRY_INTERVAL = 180
ERROR_THRESHOLD = 3

ANIMATION_TOTAL_TIME = 0.75
APPLET_STATES = [ "STARTUP", "NOCONSENT", "CONFIGURING", "OKAY", "CRITICAL", "BUSY", "ERROR", "DISCONNECTED" ]

APPLET_STATE_CHANGES = {
    "STARTUP"     : [ "OKAY", "NOCONSENT" ],
    "NOCONSENT"   : [ "CONFIGURING" ],
    "CONFIGURING" : [ "NOCONSENT", "BUSY", "OKAY", "DISCONNECTED" ],
    "OKAY"        : [ "BUSY", "CONFIGURING", "CRITICAL", "DISCONNECTED" ],
    "CRITICAL"    : [ "OKAY", "BUSY", "CRITICAL", "CONFIGURING", "DISCONNECTED" ],
    "BUSY"        : [ "OKAY", "CRITICAL", "ERROR", "DISCONNECTED" ],
    "ERROR"       : [ "OKAY" ],
    "DISCONNECTED": [ "OKAY", "BUSY", "CONFIGURING", "CRITICAL", "ERROR"], 
    }

APPLET_MENUS = [ "about", "up2date_now", "web_panel", "configure_applet", "check_now" ]

APPLET_SENSITIVE_MENU = {
    "STARTUP"     : [ "" ],
    "NOCONSENT"   : [ "about", "configure_applet", "up2date_now" ],
    "CONFIGURING" : [ "about", "up2date_now" ],
    "OKAY"        : APPLET_MENUS,
    "CRITICAL"    : APPLET_MENUS,
    "BUSY"        : [ ],
    "ERROR"       : [ "about", "up2date_now", "check_now" ],
    "DISCONNECTED": [ "about", "up2date_now", "check_now" ],
}

class rhnApplet:
    def set_state(self, new_state, use_busy_icon = 0):
        if not new_state in APPLET_STATES:
            raise "Error: invalid state %s" % new_state

        if self.current_state and not new_state in APPLET_STATE_CHANGES[self.current_state]:
            raise "Error: can't change from state %s to state %s" % (self.current_state, new_state)

        if self.refresh_timeout_tag and new_state not in [ "OKAY", "CRITICAL" ]:
            raise "Error: can't switch to state %s while refresh timer is on" % new_state

	rhn_utils.log_debug("Entering state %s" % (new_state))

        if new_state == "OKAY":
            self.animate_to("okay")
        elif new_state == "BUSY":
            if use_busy_icon:
                self.set_displayed_image("busy")
        elif new_state == "CRITICAL":
            if self.never_viewed_notices:
                self.animate_to("critical", "critical-blank")
            else:
                self.set_displayed_image("critical")
        elif new_state == "NOCONSENT":
            if self.never_viewed_consent:
                self.animate_to("noconsent", "noconsent-blank")
            else:
                self.set_displayed_image("noconsent")
        elif new_state == "DISCONNECTED":
            self.animate_to("disconnect")
        elif new_state == "ERROR":
            self.animate_to("error")

        for menu in APPLET_MENUS:
            self.menu_items[menu].set_sensitive(gtk.FALSE)

        for menu in APPLET_SENSITIVE_MENU[new_state]:
            self.menu_items[menu].set_sensitive(gtk.TRUE)

        self.current_state = new_state


    def __init__(self):
        self.destroyed = 0
        self.tooltip_text = ""
        gnome.program_init("rhn-applet", rhn_applet_version.version)
        self.tooltip = gtk.Tooltips()
        self.applet_window = eggtrayicon.create_window("rhn-applet")
        self.applet_window.connect("destroy", self.exit_applet)

        #
	# Cope with a change in the Gnome python bindings naming
	#
        try:
	    self.session = gnome.ui.gnome_master_client()
	except:
	    self.session = gnome.ui.master_client()
	if self.session:
	    gtk.Object.connect(self.session, "save-yourself",
	                       self.save_yourself)
	    gtk.Object.connect(self.session, "die", self.exit_applet)
        
        self.applet_size = 22

        menu_items = (
            ("check_now", _("_Check for updates"), _("Check for updates"), self.update_from_server),
            ("up2date_now", _("_Launch up2date..."), _("Launch up2date"), self.launch_up2date),
            ("configure_applet", _("C_onfiguration..."), _("Configuration"), self.run_first_time_druid),
            ("web_panel", _("_RHN Website..."), _("Use RHN web interface"), self.load_website),
            None,
            ("about", _("_About"), _("About..."), self.about),
            ("exit", _("_Exit"), _("Exit"), self.exit_applet),
            )
        
        self.menu = gtk.Menu()
        self.menu_items = {}
        for i in menu_items:
            if i is None:
                self.menu.add(gtk.SeparatorMenuItem())
            else:
                self.menu_items[i[0]] = gtk.MenuItem(i[1])
                self.menu_items[i[0]].connect('activate', i[3])
                self.menu_items[i[0]].show()
                self.menu.add(self.menu_items[i[0]])

        self.menu.show_all()

        self.consent = rhn_utils.get_user_config('Consent')
        self.never_viewed_consent = 1
        self.never_viewed_notices = 1
        
        self.current_image = None
        self.refresh_timeout_tag = None
        self.animate_timeout_tag = None
        self.current_state = None
        self.old_critical_text = None
	self.network_timeout_tag = None

        self.icons = rhn_applet_animation.rhnAppletIconPixbuf()

        self.icons.add_file("okay", "applet-okay.png")
        self.icons.add_file("error", "applet-error.png")
        self.icons.add_file("busy", "applet-busy.png")
        self.icons.add_file("critical", "applet-critical.png")
        self.icons.add_file("critical-blank", "applet-critical-blank.png")
        self.icons.add_file("noconsent", "applet-critical.png")
        self.icons.add_file("noconsent-blank", "applet-critical-blank.png")
        self.icons.add_file("disconnect", "applet-disconnect.png")
        
        self.event_box = gtk.EventBox()
        self.image_widget = gtk.Image()
        self.event_box.add(self.image_widget)
        self.event_box.set_events(gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.POINTER_MOTION_HINT_MASK | gtk.gdk.CONFIGURE)

#        self.applet_window.set_size_request(self.applet_size, self.applet_size)
        
        self.image_widget.show()
        self.event_box.connect("button_press_event", self.applet_face_click)
        self.image_widget.connect('destroy', self.on_destroy)

        self.applet_window.add(self.event_box)
        self.applet_window.show_all()

        self.proxy = rhn_utils.get_user_config("httpProxy")
        self.proxy_username = rhn_utils.get_user_config("proxyUser")
        self.proxy_password = rhn_utils.get_user_config("proxyPassword")
        
        self.model = rhnAppletModelGUI(self.refresh_callback,
                                       rhn_utils.get_config("server_url"),
                                       rhn_utils.get_config("uuid"),
                                       rhn_utils.get_config("use_ca_cert"))

        self.model.set_proxy(self.proxy, self.proxy_username, self.proxy_password)

        self.animator = None
        self.client = None
        self.notice_window = None
        self.rhnreg_dialog = None
        self.error_dialog = None
        self.error_threshold = 0
        self.first_time_druid = None
        self.rpm_error_dialog = None
        self.about_window = None
        self.last_error = None
        self.last_error_is_exception = 0
        self.last_error_is_network_error = 0

        self.change_number = 0

        ignored_package_str = rhn_utils.get_user_config("IgnoredPackages")

        for i in string.split(ignored_package_str, "|"):
            if i:
                self.model.add_ignored_package(i)

        # first refresh should be 2 minutes after execution; this
        # should give the rest of the user's desktop environment time
        # to load, etc, and avoid competing with nautilus or whatever
        # else is loading.  subsequent intervals will be much larger.
        
        if self.consent or self.model.need_consent() == 0:
            self.set_state("OKAY")
            self.update_tooltip(_("Waiting until first checkin..."))
        else:
            self.set_state("NOCONSENT")
            self.update_tooltip(_("Click for critical updates..."))
            
        if self.consent or self.model.need_consent() == 0:
            self.enable_refresh_timer(60000)

    def enable_refresh_timer(self, when = REFRESH_INTERVAL * 1000, force = 0):
        if self.current_state not in [ "OKAY", "CRITICAL" ]:
            raise "Can't enable timer unless in OKAY or CRITICAL state"
        if not self.refresh_timeout_tag:
            self.refresh_timeout_tag = gtk.timeout_add(when, self.refresh_handler, force)

    def disable_refresh_timer(self):
        if self.refresh_timeout_tag:
            gtk.timeout_remove(self.refresh_timeout_tag)
            self.refresh_timeout_tag = None

    def handle_gtk_events(self):
        while gtk.events_pending():
            gtk.mainiteration(gtk.FALSE)
        
    def refresh_callback(self):
        self.handle_gtk_events()

    def on_do_draw(self, *data):
        self.redraw()
        
    def on_bg_change(self, *data):
        self.redraw()        

    def on_size_allocate(self, *data):
        self.redraw()

    def on_configure(self, widget, event):
        if event.type == gtk.gdk.CONFIGURE:
            self.redraw()

    def animate_stop(self):
        self.disable_animation_timer()

        # not animating?  then our current image is correct
        if self.animator:
            self.set_displayed_image(self.animator.final_frame)
            self.animator = None

        self.redraw()

    def disable_animation_timer(self):
        if self.animate_timeout_tag:
            gtk.timeout_remove(self.animate_timeout_tag)
            self.animate_timeout_tag = None
        
    def animate_handler(self, *data):
        next_frame = self.animator.next_frame()
        if not next_frame:
            self.disable_animation_timer()
            return gtk.FALSE
        
        self.current_image = next_frame
        self.redraw()
        
        return gtk.TRUE
        
    def animate_to(self, image, cycle_image = None):

        # logic: one way animation?  then we skip this if we're asked
        # to animate to the same, and let it finish.  if it's a cycle,
        # and the start and end images are the same, then we also just
        # continue

        if self.current_image == image:
            if cycle_image:
                if self.animation_cycle == cycle_image:
                    return
            else:
                return
                
        if self.current_image:
            from_image = self.current_image.copy()
        else:
            from_image = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, 1, 8, self.applet_size, self.applet_size)
            from_image.fill(0)

        to_image = self.icons.best_match(image, self.applet_size)

        frames = rhn_applet_animation.alpha_tween(from_image, to_image, 16)
        
        self.animator = rhn_applet_animation.rhnAppletAnimation()

        # if we're already in the to_image state, let's just start cycling
        if self.current_image != to_image or cycle_image:
            self.animator.append_frames(frames)

        if cycle_image:
            cycle_frames = []
            
            to_image = self.icons.best_match(image, self.applet_size)
            from_image = self.icons.best_match(cycle_image, self.applet_size)
            cycle_frames = rhn_applet_animation.alpha_tween(to_image, from_image, 16)
            
            self.animator.append_cycle(cycle_frames)

        if not self.animate_timeout_tag:
            self.animate_timeout_tag = gtk.timeout_add(math.floor(1000 * ANIMATION_TOTAL_TIME/len(frames)), self.animate_handler)

        self.animate_handler()
        
    def set_displayed_image(self, image):
        if type(image) == type(""):
            new_image = self.icons.best_match(image, self.applet_size)
        else:
            new_image = image

        self.disable_animation_timer()

        self.current_image = new_image
        self.redraw()

    def redraw(self):
        if not self.current_image:
            return

        self.image_widget.set_from_pixbuf(self.current_image)
        
    def on_destroy(self, *data):
        self.destroyed = 1
        self.disable_refresh_timer()
        self.disable_animation_timer()

    def load_website(self, *data):
	gnome.url_show("https://rhn.redhat.com/")
        
    def launch_up2date(self, *data):
        pid = os.fork()
        if not pid:
            # fork twice to avoid zombies
            pid2 = os.fork()
            if not pid2:
                os.execv('/usr/bin/up2date', ['up2date'])
                # exec -should- never return
                os.perror(_("execv didn't execv?"))
            else:
                # call _exit so we don't mess up filehandles, etc
                os._exit(-1)
        # fall through back to main app

    def launch_rhnreg(self, *data):
        params = [ 'up2date', '--uuid', rhn_utils.get_config("uuid") ]
        if self.proxy:
            params.append("--proxy")
            params.append(self.proxy)

            if self.proxy_username:
                params.append("--proxyUser")
                params.append(self.proxy_username)
                params.append("--proxyPassword")
                params.append(self.proxy_password)
            
        pid = os.fork()
        if not pid:
            # fork twice to avoid zombies
            pid2 = os.fork()
            if not pid2:
                os.execv('/usr/bin/up2date', params)
                # exec -should- never return
                os.perror(_("execv didn't execv?"))
            else:
                # call _exit so we don't mess up filehandles, etc
                os._exit(-1)
        # fall through back to main app

    # every N seconds we poke the model to see if anything has
    # changed.  changes can be new package lists from the server, the
    # rpmdb being updated, etc.  the model caches aggressively, so
    # this isn't expensive.  this is done asynchronous to all GUI
    # updates, to try to avoid stalling the UI
    
    def refresh_handler(self, force = 0):
        self.refresh(force)

    def dump_memory(self):
        pid = os.getpid()
        f = open("/proc/%s/statm" % pid)
        print "memory: %s" % f.read()
        
    def refresh(self, force=0):
        old_tip = self.tooltip_text
        old_state = self.current_state

        self.disable_refresh_timer()
	self.disable_network_timer()
            
        self.set_state("BUSY", use_busy_icon = force)
        self.update_tooltip(_("Checking RHN for updates..."))
        self.handle_gtk_events()
	self.last_error = None
	self.last_error_is_network_error = 0

        try:
            self.model.refresh(force)
        except rhnAppletException, e:
            self.error_threshold = self.error_threshold + 1
            if self.error_threshold >= ERROR_THRESHOLD:
                # simple error, we can handle this just by presenting a string to the user
                self.last_error = str(e)
                self.last_error_is_exception = 0
	    self.last_error_is_network_error = self.is_network_error(str(e))
            rhn_utils.log_debug("Applet: " +  str(e))
        except:
            self.error_threshold = self.error_threshold + 1
            if self.error_threshold >= ERROR_THRESHOLD:
                e_type, e_value = sys.exc_info()[:2]
                exc = StringIO()
            
                exc.write("Exception type %s\n" % (e_type,))
                exc.write("\nException Handler Information\n")
                traceback.print_exc(None, exc)

                self.last_error = exc.getvalue()
                self.last_error_is_exception = 1
		self.last_error_is_network_error = self.is_network_error(
		               "%s" % (e_value))

                rhn_utils.log_debug("Except: " + exc.getvalue())
        else:
            # no error.  clear threshold.
            self.error_threshold = 0

	if self.last_error_is_network_error:
	    self.update_tooltip(_("Unable to connect to RHN..."))
	    self.set_state("DISCONNECTED")
            self.disable_refresh_timer()
	    self.enable_network_timer()
	    return gtk.FALSE
        if self.last_error:
            self.disable_refresh_timer()
	    self.update_tooltip(_("Error connecting to RHN..."))
	    self.set_state("ERROR")
	    return gtk.FALSE

        if self.tooltip_text == _("Checking RHN for updates..."):
            self.update_tooltip(old_tip)

        # it is possible that the applet was destroyed during the time it
        # took to update the model.  If the applet is gone, bail now.
        if self.destroyed:
            return gtk.FALSE

        if self.model.change_number != self.change_number:
            needed_packages, ignored_needed_packages = self.model.needed_packages()
            self.system_needs_packages(needed_packages, ignored_needed_packages)

            self.change_number = self.model.change_number
        else:
            self.set_state(old_state)
        
        self.disable_refresh_timer()
            
        self.enable_refresh_timer()
        return gtk.FALSE

    #
    # Detection and handling of network related errors, the
    # server may be unreachable, or refusing connections, quite
    # common in case of laptops. If such an error is detected
    # the applet will try to retry the connections after a timeout
    # of NETWORK_RETRY_INTERVAL seconds (one minute)
    # until it suceeeds reaching the server and then exit the
    # DISCONNECTED state
    #
    def is_network_error(self, msg):
        # print "is_network_error: '%s'" % (msg)
	if msg.find("SysCallError") >= 0 and msg.find("104") >= 0:
	    return 1
        if msg.find("onnection") >= 0:
	    return 1
        if msg.find("etwork") >= 0:
	    return 1
        if msg.find("certificate verify failed") >= 0:
	    return 0
        if msg.find("SSL") >= 0:
	    return 1
	return 0
        
    def network_retry_handler(self, force):
	rhn_utils.log_debug("Retrying to connect...")
	self.refresh(force)

    def enable_network_timer(self, when = NETWORK_RETRY_INTERVAL * 1000, force = 0):
        if self.current_state != "DISCONNECTED":
            raise "Can't enable network timer unless in DISCONNECTED state"
        if not self.network_timeout_tag:
            self.network_timeout_tag = gtk.timeout_add(when, self.network_retry_handler, force)

    def disable_network_timer(self):
        if self.network_timeout_tag:
            gtk.timeout_remove(self.network_timeout_tag)
            self.network_timeout_tag = None



    def system_needs_packages(self, needed_packages, ignored_needed_packages):
        ignored_dict = {}
        for i in ignored_needed_packages:
            ignored_dict[i] = 1
            
        needed_and_not_ignored = filter(lambda pkg, ign=ignored_dict: not ign.has_key(pkg["name"]), needed_packages)

        ignored_count = len(needed_packages) - len(needed_and_not_ignored)
        
        if len(needed_and_not_ignored):
            if not self.notice_window:
                self.never_viewed_notices = 1
            self.set_state("CRITICAL")

            if self.notice_window:
                self.refresh_notice_window(needed_packages, ignored_needed_packages)

            num_needed = len(needed_and_not_ignored)
            if num_needed > 1:
                self.update_tooltip(_("%d updates available (%d ignored)") % (num_needed, ignored_count));
            else:
                self.update_tooltip(_("%d update available (%d ignored)") % (num_needed, ignored_count));
                
        else:
            self.set_state("OKAY")

            if self.notice_window:
                self.refresh_notice_window(needed_packages, ignored_needed_packages)

            self.update_tooltip(_("No updates available (%d ignored)") % ignored_count);

    def update_tooltip(self, tip):
        self.tooltip_text = tip
        self.tooltip.set_tip(self.applet_window, tip)
        
    def update_from_server(self, widget=None):
        self.refresh(force = 1)
        
    def user_consented(self):
        self.consent = 1
        rhn_utils.set_user_config('Consent', self.consent)

        rhn_utils.set_user_config("httpProxy", self.proxy)
        rhn_utils.set_user_config("proxyUser", self.proxy_username)
        rhn_utils.set_user_config("proxyPassword", self.proxy_password)
        
        self.model.set_proxy(self.proxy, self.proxy_username, self.proxy_password)
        
    def set_proxy(self, proxy = '', u = '', p = ''):
        self.proxy = proxy
        self.proxy_username = u
        self.proxy_password = p
       
    def notice_window_closed(self):
        rhn_utils.log_debug("closed")
        self.notice_window = None

        ignored_package_str = string.join(self.model.ignored_package_list(), "|")
        rhn_utils.set_user_config("IgnoredPackages", ignored_package_str)

    def help (self, args):
        gnome.help.goto ("file:///usr/share/doc/rhn-applet-2.1.7/index.html")
        

    def exit_applet(*args):
        gtk.mainquit()
        return
        
    def save_yourself(self, *args):
	if self.session:
	    self.session.set_clone_command(1, ["/usr/bin/rhn-applet-gui"])
	    self.session.set_restart_command(1, ["/usr/bin/rhn-applet-gui"])

        return gtk.TRUE

    def about(self, *data):
        if self.about_window:
            return

        self.about_window = rhnAppletAboutWindow(self)

    def about_dialog_closed(self):
        self.about_window = None
        
    def rhnreg_dialog_closed(self):
        self.rhnreg_dialog = None

    def error_dialog_closed(self):
        self.error_dialog = None
        self.last_error = None
        self.last_error_is_exception = 0
        self.last_error_is_network_error = 0
        self.set_state("OKAY")
        self.update_tooltip(_("Waiting before checkin..."))

        self.enable_refresh_timer()

    def run_first_time_druid(self, *data):
        if not self.first_time_druid:
            self.disable_refresh_timer()
            self.set_state("CONFIGURING")

            if self.notice_window:
                self.notice_window.close_window()
            
            self.first_time_druid = rhnAppletFirstTimeDruid(self, self.proxy, self.proxy_username, self.proxy_password)
        
    def first_time_druid_closed(self, remove):
        if remove:
            self.destroyed = 1
            gtk.mainquit()

        self.never_viewed_consent = 0
        self.first_time_druid = None
        if not self.consent and self.model.need_consent() == 1:
            self.set_state("NOCONSENT")
            return
        
        self.set_state("OKAY")
        self.enable_refresh_timer(when = 250, force = 1)
        
    def applet_face_click(self, window, event, *data):
        if event.button == 3:
            self.menu.popup(None, None, None, 0, event.time)
            return

        if self.current_state in [ "CRITICAL", "NOCONSENT" ]:
            self.animate_stop()
        
        if not self.consent and self.model.need_consent() == 1:
            self.run_first_time_druid()
            return
        
        if not self.current_state in [ "OKAY", "ERROR", "DISCONNECTED", "CRITICAL" ]:
            return
        
        if not os.access("/etc/sysconfig/rhn/systemid", os.F_OK) \
	     and not self.rhnreg_dialog and self.model.need_consent() == 1:
            self.rhnreg_dialog = rhnRegistrationPromptDialog(self)

        if self.last_error:
            if self.error_dialog:
                return
            if self.last_error_is_exception:
                self.error_dialog = rhnAppletExceptionDialog(self, self.last_error)
            else:
                self.error_dialog = rhnAppletErrorDialog(self, self.last_error)
            return
            
        # clicked the face while it was loaded, and not while telling
        # them to register?  well, let's close it
        
        self.never_viewed_notices = 0
        if self.notice_window and not self.rhnreg_dialog:
            self.notice_window.close_window()
            return

        if not self.notice_window:
            self.notice_window = rhnAppletNoticeWindow(self)

        self.refresh_notice_window()

        if self.rhnreg_dialog:
            self.rhnreg_dialog.set_transient(self.notice_window)
            self.rhnreg_dialog.raise_()

    def refresh_notice_window(self, needed_packages = None, ignored_needed_packages = None):
        self.notice_window.clear_window()

        if not needed_packages or not ignored_needed_packages:
            needed_packages, ignored_needed_packages = self.model.needed_packages()

        names = {}
        for pkg in needed_packages:
            if not names.has_key(pkg["name"]):
                names[pkg["name"]] = []
                
            names[pkg["name"]].append(pkg)

        ordered_names = names.keys()
        ordered_names.sort();
        rhn_utils.log_debug("NN: %s" % ordered_names)

        for name in ordered_names:
            rhn_utils.log_debug("foo: %s" % names[name])

            available = string.join(map(lambda p: p["nevr"], names[name]), ", ")
	    # drop the ending ':' if there is no epoch
	    if len(available) >= 1 and available[-1] == ":":
	        available = available[:-1]
	        

            installed = self.model.installed_package(name)
            self.notice_window.add_package(name,
                                           string.join((installed["name"],
                                                        installed["version"],
                                                        installed["release"]), "-"),
                                           available)

        critical_text = []

        for a in self.model.alerts():
            if a.is_unsupported_kernel_alert():
                kernel = a.alert_data()
                critical_text.append(_("""
You are running kernel-%s, but it is not installed in RPM format.  It is
highly recommended that you run the official Red Hat Linux kernels.
By running a custom kernel, you will miss out on any security fixes
and functionality enhancements provided by Red Hat Linux, and your
configuration is unsupported.
""") % kernel)
            if a.is_kernel_alert():
                running, installed = a.alert_data()
        
                critical_text.append(_("""
Your system is currently running <b>%s</b>, but the newest installed
kernel is <b>%s</b>.  It is recommended that you <b>reboot</b> at the first
opportunity to test this new kernel.
""") % (self.model.pkg_as_nvr(running), self.model.pkg_as_nvr(installed)))

            if a.is_up2date_alert():
                current, latest = a.alert_data()
                critical_text.append(_("""
Your system currently has <b>%s</b> installed, but the latest
available version is <b>%s</b>.  It is recommended that you <b>upgrade
to the latest up2date</b> before updating any other packages.
""") % (self.model.pkg_as_nvr(current), self.model.pkg_as_nvr(latest)))

            if a.is_source_alert():
	        list = a.alert_data()
		critical_text.append(_("""
The applet has been unable to access the following information sources
in its last attempts:
%s
""" % (list)))

        if critical_text:
            if self.old_critical_text != critical_text:
                self.notice_window.set_critical(string.join(critical_text, "<br><br>"), critical_active = 1)
            else:
                self.notice_window.set_critical(string.join(critical_text, "<br><br>"), critical_active = 0)
            self.old_critical_text = critical_text
        else:
            self.notice_window.remove_critical()

        self.notice_window.redraw_lists()

    def set_ignored(self, name, new_value):
        self.never_viewed_notices = 0
        
        if self.model.is_package_ignored(name) and not new_value:
            self.model.remove_ignored_package(name)

        if not self.model.is_package_ignored(name) and new_value:
            self.model.add_ignored_package(name)

        needed_packages, ignored_needed_packages = self.model.needed_packages()
        self.system_needs_packages(needed_packages, ignored_needed_packages)

    def run(self):
        gtk.mainloop()


