#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <libintl.h>
#include <sys/wait.h>
#include <glob.h>

#include <glib.h>
#include <glib/gstdio.h>
#include <gio/gio.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>

#include "notify-utils.h"
#include "update-notifier.h"
#include "update.h"
#include "trayappletui.h"

#define UPGRADE_CHECKER PACKAGE_LIB_DIR"/update-notifier/apt-check"
#define PACKAGE_SYSTEM_LOCKED PACKAGE_LIB_DIR"/update-notifier/package-system-locked"

typedef struct {
   const char *id;         // the action identifier
   const char *command;    // the command to execude
   const char *desc;       // the user-visible description
} action_t;

static action_t actions[] = {
   {
      "install-all",
      "/usr/bin/update-manager --no-update --install-all",
      N_("Install Now"),
   },
   {
      "show-updates",
      "/usr/bin/update-manager --no-update",
      N_("Show Updates"),
   },
};

#define DEFAULT_ACTION_IDX 1
G_STATIC_ASSERT (DEFAULT_ACTION_IDX < G_N_ELEMENTS (actions));

enum { 
   NOTIFICATION_DEFAULT, 
   NOTIFICATION_IGNORE, 
   NOTIFICATION_SHOW_UPDATES 
};

static inline void
g_debug_update(const char *msg, ...)
{
   va_list va;
   va_start(va, msg);
   g_logv("update",G_LOG_LEVEL_DEBUG, msg, va);
   va_end(va);
}

static void
launch_update_action (action_t *action, TrayApplet *ta, GAppLaunchContext *context) {
    UpdateTrayAppletPrivate *priv = ta->user_data;
    g_autoptr (GAppInfo) app_info = NULL;
    g_autoptr (GError) error = NULL;

    app_info = g_app_info_create_from_commandline (action->command,
                                                   g_app_info_get_name (G_APP_INFO (priv->software_updater_app)),
                                                   G_APP_INFO_CREATE_SUPPORTS_STARTUP_NOTIFICATION,
                                                   NULL);
    g_return_if_fail (app_info != NULL);

    g_app_launch_context_setenv (context, "GIO_LAUNCHED_DESKTOP_FILE",
                                 g_desktop_app_info_get_filename (priv->software_updater_app));
    if (!g_app_info_launch (app_info, NULL, context, &error)) {
        g_warning ("Failed to launch %s: %s",
                   g_app_info_get_id (G_APP_INFO (priv->software_updater_app)),
                   error->message);
    }
}

#ifndef HAVE_APP_INDICATOR
static gboolean
gtk_status_icon_click_activate_cb (GtkWidget *widget, 
	     TrayApplet *ta)
{
   UpdateTrayAppletPrivate *priv = (UpdateTrayAppletPrivate*)ta->user_data;
   g_autoptr (GAppLaunchContext) context = NULL;

   // on double click we get two activate signals, so slow down things
   // here a bit to avoid double starting
   static time_t last_action = 0;
   if (time(NULL) - last_action < 1)
      return TRUE;

   context = g_app_launch_context_new ();
   launch_update_action (&actions[DEFAULT_ACTION_IDX], ta, context);
   last_action = time(NULL);
   return TRUE;
}
#endif

static void
update_trayicon_update_tooltip (TrayApplet *ta, int num_upgrades)
{
   //g_print("update_tooltip: %p %p %p\n", ta, ta->tooltip, ta->eventbox);
   gchar *updates;

   updates = g_strdup_printf(ngettext("There is %i update available",
				      "There are %i updates available",
				      num_upgrades),
			     num_upgrades);
   tray_applet_ui_set_tooltip_text(ta, updates);
   g_free(updates);
}


static void 
cb_action(GObject *self, void *user_data)
{
   TrayApplet *ta = (TrayApplet*)user_data;
   UpdateTrayAppletPrivate *priv = ta->user_data;
   g_autoptr (GAppLaunchContext) context = NULL;

   int i = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(self), "action"));
   context = g_app_launch_context_new ();
   launch_update_action (&actions[i], ta, context);
}

static void 
cb_preferences(GObject *self, void *user_data)
{
   TrayApplet *ta = user_data;
   UpdateTrayAppletPrivate *priv = ta->user_data;
   g_autoptr (GAppLaunchContext) context = g_app_launch_context_new ();
   g_autoptr (GError) error = NULL;

   if (!g_app_info_launch (G_APP_INFO (priv->software_properties_app), NULL, context, &error))
      g_warning ("failed to launch preferences: %s", error->message);
}

static void 
cb_toggled_show_notifications(GObject *self, void *data)
{
      TrayApplet *ta = (TrayApplet*)data;
      UpdateTrayAppletPrivate *priv = (UpdateTrayAppletPrivate*)ta->user_data;

      gboolean b = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(self));
      g_settings_set_boolean(ta->un->settings,
                             SETTINGS_KEY_NO_UPDATE_NOTIFICATIONS, !b);
      

      if(priv->active_notification != NULL) {
	 notify_notification_close(priv->active_notification, NULL);
	 g_clear_object(&priv->active_notification);
      }
}


static void
update_trayicon_create_menu(TrayApplet *ta)
{
	UpdateTrayAppletPrivate *priv = ta->user_data;
	GtkWidget *menuitem;
	int i;

	ta->menu = gtk_menu_new ();

	for (i = 0; i < G_N_ELEMENTS (actions); i++) {
	   menuitem = gtk_menu_item_new_with_label (_(actions[i].desc));

	   gtk_menu_shell_append (GTK_MENU_SHELL (ta->menu), menuitem);
	   g_object_set_data(G_OBJECT(menuitem), "action", GINT_TO_POINTER(i));
	   g_signal_connect(G_OBJECT(menuitem), "activate", 
			    G_CALLBACK(cb_action), ta);
	}

	menuitem = gtk_separator_menu_item_new();
	gtk_menu_shell_append (GTK_MENU_SHELL (ta->menu), menuitem);

	menuitem = gtk_check_menu_item_new_with_label(_("Show notifications"));
	gboolean b = g_settings_get_boolean(ta->un->settings,
	                                    SETTINGS_KEY_NO_UPDATE_NOTIFICATIONS);
	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), !b);
	gtk_menu_shell_append (GTK_MENU_SHELL (ta->menu), menuitem);
	g_signal_connect(G_OBJECT(menuitem), "toggled", 
			 G_CALLBACK(cb_toggled_show_notifications), ta);

	if (priv->software_properties_app) {
	   menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_PREFERENCES, NULL);
	   gtk_menu_shell_append (GTK_MENU_SHELL (ta->menu), menuitem);
	   g_signal_connect(G_OBJECT(menuitem), "activate",
	                    G_CALLBACK(cb_preferences), ta);
	}

	gtk_widget_show_all (ta->menu);
}

/* this tells the trayicon that apt is downloading something */
void 
update_apt_is_running(TrayApplet *ta, gboolean is_running)
{
   g_debug_update("update_apt_is_running: %i",is_running);
   if(ta == NULL)
      return;

   // update internal status
   UpdateTrayAppletPrivate *priv = (UpdateTrayAppletPrivate*)ta->user_data;
   priv->apt_is_running = is_running;

   if(is_running) {
#ifdef HAVE_APP_INDICATOR
      // we can't do fancy stuff like the gray-out with app-indicator,
      // so we just hide the tray thing here
      tray_applet_ui_set_visible(ta, FALSE);
#else
      // gray out the icon if apt is running, we do this only once,
      // after the first time, the storage_type changes from ICON_NAME to
      // IMAGE_PIXBUF
      if(gtk_status_icon_get_storage_type(ta->tray_icon) == GTK_IMAGE_ICON_NAME) {
	 GdkPixbuf *src = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(),
						   gtk_status_icon_get_icon_name(ta->tray_icon),
						   gtk_status_icon_get_size(ta->tray_icon), 
						   0, 
						   NULL);
	 GdkPixbuf *inactive = gdk_pixbuf_copy(src);
	 gdk_pixbuf_saturate_and_pixelate(src, inactive, 0.0, FALSE);
	 gtk_status_icon_set_from_pixbuf(ta->tray_icon, inactive);
	 g_object_unref(src);
	 g_object_unref(inactive);
      }

      // and update the tooltip
      tray_applet_ui_set_tooltip_text(ta->tray_icon, _("A package manager is working"));
      // and show it
      tray_applet_ui_set_visible(ta->tray_icon, TRUE);
#endif

      if(priv->active_notification != NULL) {
	 notify_notification_close(priv->active_notification, NULL);
	 g_clear_object(&priv->active_notification);
      }
   } else {
      tray_applet_ui_set_icon(ta, ta->name);
   }
}

static void
on_notification_action(NotifyNotification *notification, char* id, gpointer user_data)
{
    TrayApplet *ta = user_data;
    UpdateTrayAppletPrivate *priv = ta->user_data;
    g_autoptr (GAppLaunchContext) context = NULL;
    const char* activation_token;
    int action_idx = DEFAULT_ACTION_IDX;
    gboolean found = FALSE;

    g_return_if_fail (ta != NULL);

    for (int i = 0; i < G_N_ELEMENTS (actions); i++) {
        if (g_str_equal (id, actions[i].id)) {
            action_idx = i;
            found = TRUE;
            break;
        }
    }

    if (!found && !g_str_equal (id, "default"))
        g_warning ("received bad notification action; fallback to default");

    context = notification_app_launch_context_new (notification);
    launch_update_action (&actions[action_idx], ta, context);
}

// actually show the notification 
static gint 
show_notification(gpointer user_data)
{
   TrayApplet *ta = (TrayApplet *)user_data;
   UpdateTrayAppletPrivate *priv = (UpdateTrayAppletPrivate*)ta->user_data;
   g_autoptr (GSettings) settings = NULL;
   g_autoptr (NotifyNotification) n = NULL;
   g_autofree char *title = NULL;
   g_autofree char *desc = NULL;
   g_autofree char *app_icon_name = NULL;
   g_autofree char *app_id_no_suffix = NULL;
   const char *app_name;
   const char *app_id;

   // apt is running, no point in showing a notification
   if(priv->apt_is_running) 
      return G_SOURCE_CONTINUE;

   // check if the update-icon is still visible (in the delay time a 
   // update may already have been performed)
   if(!tray_applet_ui_get_visible(ta))
      return G_SOURCE_REMOVE;

   app_name = g_app_info_get_name (G_APP_INFO (priv->software_updater_app));
   app_id = g_app_info_get_id (G_APP_INFO (priv->software_updater_app));
   app_icon_name = g_desktop_app_info_get_string (priv->software_updater_app,
                                                  G_KEY_FILE_DESKTOP_KEY_ICON);

   g_return_val_if_fail (app_name && app_id, G_SOURCE_REMOVE);

   // now show a notification handle 
   title = g_strdup_printf(ngettext("%i Update Available",
                                    "%i Updates Available",
                                     priv->num_upgrades),\
                                     priv->num_upgrades);

   /* TRANSLATORS: %s is the already translated name for the update-manager.desktop application */
   desc = g_strdup_printf(_("You can review them in the %s."), app_name);

   app_id_no_suffix = g_strndup (app_id, strlen (app_id) - strlen (".desktop"));
   n = notify_notification_new (title, desc, NULL);
   notify_notification_set_app_icon (n, app_icon_name);
   notify_notification_set_hint (n, "desktop-entry", g_variant_new_string (app_id_no_suffix));
   notify_notification_set_timeout (n, 60*1000);
   notify_notification_add_action (n, "default", _(actions[DEFAULT_ACTION_IDX].desc),
                                   on_notification_action, ta, NULL);
   for (int i = 0; i < G_N_ELEMENTS (actions); i++) {
      notify_notification_add_action (n, actions[i].id, _(actions[i].desc),
                                      on_notification_action, ta, NULL);
   }
   notify_notification_show(n, NULL);
   // save the notification handle
   if (priv->active_notification)
      g_object_unref(priv->active_notification);
   priv->active_notification = g_steal_pointer (&n);

   settings = g_settings_new (SETTINGS_UM_SCHEMA);
   g_settings_set_int64 (settings, SETTINGS_UM_KEY_LAST_LAUNCH, time(NULL));

   // remove this from the timeout now
   return G_SOURCE_REMOVE;
}

static void 
show_error(TrayApplet *ta, gchar *error_str)
{
   tray_applet_ui_set_tooltip_text(ta, error_str);
   tray_applet_ui_set_icon(ta, "dialog-error");
   tray_applet_ui_set_visible(ta, TRUE);
}

static gboolean
outdated_nag(TrayApplet *ta)
{
   struct stat buf;
   if ((stat("/var/lib/apt/periodic/update-success-stamp", &buf) == 0) &&
       (time(NULL) - buf.st_mtime > OUTDATED_NAG_AGE) ) {
      tray_applet_ui_set_visible (ta, TRUE);
      ta->name = "gtk-dialog-warning-panel";
      tray_applet_ui_set_icon(ta, ta->name);
      tray_applet_ui_set_tooltip_text(ta,
				  _("The update information is outdated. "
				    "This may be caused by network "
				    "problems or by a repository that "
				    "is no longer available. "
				    "Please update manually "
                                    "by selecting 'Show updates' from "
                                    "the indicator menu, and watching "
                                    "for any failing repositories."
				 ));
   }
   return FALSE;
}

// use package-system-locked to check
// if the dpkg lock is taken currently or not
//
// if uncertain, return FALSE 
static gboolean
dpkg_lock_is_taken (void)
{
    gchar *cmd[] = { "pkexec", PACKAGE_SYSTEM_LOCKED, NULL };
    gint exit_status;
    GError *err = NULL;

    if(!g_spawn_sync(NULL, cmd, NULL, G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL,
                NULL, NULL, NULL, NULL, &exit_status, &err)) {
        g_warning("failed to run " PACKAGE_SYSTEM_LOCKED ": %s", err->message);
        g_error_free(err);
        return FALSE;
    }

    if(!WIFEXITED(exit_status)) {
        g_warning(PACKAGE_SYSTEM_LOCKED " exited abnormally with code %i", exit_status);
        return FALSE;
    }

    exit_status = WEXITSTATUS(exit_status);
    g_debug_update ("is_package_system_locked: " PACKAGE_SYSTEM_LOCKED "returned %i", exit_status);
    return exit_status == 2;
}

#if 0
// ask devicekit.Power if we run on battery
static gboolean
running_on_battery (void)
{
   DBusGConnection *connection;
   GError *error;
   DBusGProxy *proxy;
   gboolean on_battery = FALSE;
  
   error = NULL;
   connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
   if (connection == NULL) {
      g_debug_update ("Failed to open connection to bus: %s", error->message);
      g_error_free (error);
      return FALSE;
   }

  proxy = dbus_g_proxy_new_for_name (connection,
				     "org.freedesktop.DeviceKit.Power", 
				     "/org/freedesktop/DeviceKit/Power",
				     "org.freedesktop.DBus.Properties");
  error = NULL;
  if (!dbus_g_proxy_call (proxy, "Get", &error, 
			  G_TYPE_STRING, "org.freedesktop.DeviceKit.Power", 
			  G_TYPE_STRING, "on_battery",
			  G_TYPE_INVALID,
                          G_TYPE_BOOLEAN, &on_battery, 
			  G_TYPE_INVALID)) {
     g_debug_update ("failed Get dbus call: %s", 
		     error?error->message:"no error given");
     if(error)
	g_error_free (error);
     return FALSE;
  }
  g_debug_update ("on_battery: %i", on_battery);
  return on_battery;
}
#endif

static gboolean
security_updates_are_installed_unattended(void)
{
   int ret;
   GError *error = NULL;

   // run apt_check.py in "check if we install updates unattended" mode
   // a exit status > 0 indicates that its unattended-upgrades is used
   if ( g_file_test ("/usr/bin/unattended-upgrades", 
		     G_FILE_TEST_IS_EXECUTABLE) ) {
      char *cmd[] = { "/usr/bin/nice",
		      "/usr/bin/ionice", "-c3",
		      UPGRADE_CHECKER, 
		      "--security-updates-unattended",	      
		      NULL };

      if (g_spawn_sync("/", cmd, NULL, 0, NULL, NULL, 
		       NULL, NULL, &ret, &error)) {
	 g_debug("--security-updates-unattended: %i", WEXITSTATUS(ret));
	 if( WEXITSTATUS(ret) > 0 )
	    return TRUE;
      } else if (error) {
	 g_print("error: %s\n", error->message);
      }
   }
   return FALSE;
}

// check if the security auto launch interval is over
// and if the user is not using auto install of security
// updates
static gboolean
auto_launch_security_now(UpdateTrayAppletPrivate *priv, 
			 time_t now, 
			 time_t last_launch)
{

   // no security updates
   if (priv->num_security == 0)
      return FALSE;
	 
   // security updates, but already launched recently
   if ((last_launch + AUTOLAUNCH_MINIMAL_SECURITY_INTERVAL) > now) {
      g_debug_update("security updates, but update-manager was launched "
		     "within the AUTOLAUNCH_MINIMAL_SECURITY_INTERVAL");
      return FALSE;
   }
   
   // if security updates are installed unattended, there is nothing
   // to do for us
   if (security_updates_are_installed_unattended())
      return FALSE;

   g_debug_update("security updates, auto-launching");
   return TRUE;
}

// Like ctime, but without the annoying trailing newline.  Caller must
// g_free the result.
static gchar *
readable_timestamp(time_t time)
{
   GDateTime *datetime;
   gchar *formatted;

   datetime = g_date_time_new_from_unix_local (time);
   formatted = g_date_time_format (datetime, "%a %b %e %T %Y");
   g_date_time_unref (datetime);
   return formatted;
}

// check the logs of dpkg and apt for timestamps, the idea
// is to not auto launch if dpkg/apt were run manually by the
// user
static time_t
newest_log_file_timestamp(void)
{
   struct stat buf;
   int i, j;
   time_t newest_log_stamp = 0;

   char *log_glob[] = { "/var/log/dpkg.log*",
		    "/var/log/apt/term.log*",
		    NULL };

   for (i=0; log_glob[i] != NULL; i++) 
   {
      glob_t pglob;
      if(glob(log_glob[i], 0, NULL, &pglob) != 0) {
	 g_warning("error from glob %s", log_glob[i]);
	 continue;
      }
      for(j=0;j < pglob.gl_pathc; j++) {
	 const char *log = pglob.gl_pathv[j];
	 time_t mtime;
	 gchar *timestamp;

	 if(g_stat(log, &buf) <0) {
	    g_warning("can't stat %s", log);
	    continue;
	 }
	 if(buf.st_size == 0) {
	    g_warning("log file empty (logrotate?) %s", log);
	    continue;
	 }

	 mtime = buf.st_mtime;
	 timestamp = readable_timestamp (mtime);
	 g_debug_update ("mtime from %s: %i (%s)", log, mtime, timestamp);
	 g_free (timestamp);

	 newest_log_stamp = MAX(mtime, newest_log_stamp);
	 timestamp = readable_timestamp (newest_log_stamp);
	 g_debug_update ("last_launch from %s: %i (%s)", log, newest_log_stamp, timestamp);
	 g_free (timestamp);
      }
      globfree(&pglob);
   }
   return newest_log_stamp;
}

// check if the auto launch interval is over and its 
// time to launch again and if the dpkg lock is currently 
// not taken
static gboolean 
auto_launch_now (TrayApplet *ta)
{
   UpdateTrayAppletPrivate *priv = (UpdateTrayAppletPrivate*)ta->user_data;
   int interval_days = 0;
   time_t last_launch = 0;

   if (dpkg_lock_is_taken())
      return FALSE;

#if 0 // disabled because we need more cleverness here in order to cover
      // the case where people always work on battery (and charge overnight)
   if (running_on_battery())
      return FALSE;
#endif

   // when checking for regular updates honor the 
   // regular-auto-launch-interval
   interval_days = g_settings_get_int(ta->un->settings,
					SETTINGS_KEY_AUTO_LAUNCH_INTERVAL);
   g_debug_update ("interval_days: %i", interval_days);

   if (interval_days <= 0) 
      return TRUE;

   // check last launch time 
   GSettings *um_settings = g_settings_new(SETTINGS_UM_SCHEMA);
   last_launch = g_settings_get_int64(um_settings,
                                      SETTINGS_UM_KEY_LAST_LAUNCH);
   g_debug_update ("last_launch: %i (%s)", last_launch, ctime(&last_launch));
   g_object_unref(um_settings);

   time_t now = time(NULL);
   if (auto_launch_security_now(priv, now, last_launch))
      return TRUE;

   g_debug_update("time now %i (%s), delta: %i", now, ctime(&now), now-last_launch);
   if ((last_launch + (24*60*60*interval_days)) < now) {
      g_debug_update ("need to auto launch");
      return TRUE;
   }

   return FALSE;
}

gboolean
update_check (TrayApplet *ta)
{
   if(ta == NULL)
      return FALSE;

   g_debug_update ("update_check()");
   UpdateTrayAppletPrivate *priv = (UpdateTrayAppletPrivate*)ta->user_data;

   priv->num_upgrades = 0;
   priv->num_security = 0;
   int exit_status = 0;
   GError *error = NULL;

   char *cmd[] = { "/usr/bin/nice",
		   "/usr/bin/ionice", "-c3",
		   UPGRADE_CHECKER, 
		   NULL };
   char *ret;

   if(g_spawn_sync(NULL, cmd, NULL,  
		   G_SPAWN_STDOUT_TO_DEV_NULL, 
		   NULL, NULL, NULL, &ret,
		   &exit_status, &error)) {

      // check if we are running from the live-cd, it
      // symlinks apt-check to /bin/true
      if(exit_status == 0 && strlen(ret) == 0 &&
	 g_file_test (UPGRADE_CHECKER, G_FILE_TEST_IS_SYMLINK) ) {
	 g_free(ret);
	 return TRUE;
      }

      // read the value from childs stderr, E: indicates a problem
      if(ret[0] == 'E') {
	 GString *error = g_string_new("");
	 if(strlen(ret) > 3) 
	    g_string_append_printf(error,
				   _("An error occurred, please run "
				      "Package Manager from the "
				      "right-click menu or apt-get in "
				      "a terminal to see what is wrong.\n"
				      "The error message was: '%s'. "),
				    &ret[2]);
	 else
	    g_string_append(error, _("An error occurred, please run "
				      "Package Manager from the "
				      "right-click menu or apt-get in "
				      "a terminal to see what is wrong."));
	 g_string_append(error, _("This usually means that your installed "
				    "packages have unmet dependencies"));
	 show_error(ta, error->str);
	 g_string_free(error, TRUE);
	 g_free(ret);
	 return TRUE;
	 
      }

      // we get "number_of_upgrades;number_of_security_upgrades" 
      // (e.g. "15;2")
      gchar **ret_array = g_strsplit(ret, ";", 2);
      if(g_strv_length(ret_array) < 2)  {
	 show_error(ta, _("A problem occurred when checking for the updates."));
 	 g_free(ret);
	 g_strfreev(ret_array);
	 return TRUE;
      }
      priv->num_upgrades = atoi(ret_array[0]);
      priv->num_security = atoi(ret_array[1]);
      g_free(ret);
      g_strfreev(ret_array);
   } else
      g_warning("Error launching %s", UPGRADE_CHECKER);
   
   g_debug_update("%s returned %i (security: %i)", UPGRADE_CHECKER, priv->num_upgrades, priv->num_security);

   if (priv->num_upgrades == 0) {
      // check if the periodic file is very old
      struct stat buf;
      if ((stat("/var/lib/apt/periodic/update-success-stamp", &buf) == 0) &&
	  (time(NULL) - buf.st_mtime > OUTDATED_NAG_AGE) ) 
	 g_timeout_add_seconds(OUTDATED_NAG_WAIT, (GSourceFunc)outdated_nag, ta);

      tray_applet_ui_set_visible (ta, FALSE);
      if(priv->active_notification != NULL) {
	 notify_notification_close(priv->active_notification, NULL);
	 g_clear_object(&priv->active_notification);
      }
      return TRUE;
   } 

   if (priv->num_security == 0)
      ta->name = "software-update-available-symbolic";
   else
      ta->name = "software-update-urgent-symbolic";
   tray_applet_ui_set_icon(ta, ta->name);

   // update the tooltip
   update_trayicon_update_tooltip(ta, priv->num_upgrades);

   if (auto_launch_now(ta) &&
       !g_settings_get_boolean(ta->un->settings, SETTINGS_KEY_NO_UPDATE_NOTIFICATIONS))
   {
      // show the notification with some delay. otherwise on a login
      // the origin of the window is 0,0 and that looks ugly
      g_timeout_add_seconds(5, show_notification, ta);
   }

   // if we are already visible, skip the rest
   if(tray_applet_ui_get_visible (ta))
      return TRUE;

   // show the icon
   tray_applet_ui_set_visible(ta, TRUE);

   return TRUE;
}

void 
update_tray_icon_init(TrayApplet *ta, GDesktopAppInfo *software_updater_app)
{
   // create the private data struct
   UpdateTrayAppletPrivate *priv = g_new0(UpdateTrayAppletPrivate, 1);

   priv->software_updater_app = g_object_ref (software_updater_app);
   priv->software_properties_app = g_desktop_app_info_new ("software-properties-gtk.desktop");

   priv->apt_is_running = FALSE;
   priv->active_notification = NULL;
   ta->user_data = priv;

   // create the indicator/icon immediately; we use this enough that it
   // probably isn't worth trying to save memory by avoiding it
   tray_applet_ui_ensure (ta);

#ifndef HAVE_APP_INDICATOR
   // the default action for the gtk_status_icon
   g_signal_connect (G_OBJECT(ta->tray_icon),
		     "activate",
		     G_CALLBACK (gtk_status_icon_click_activate_cb),
		     ta);
#endif

   /* Menu initialization */
   update_trayicon_create_menu (ta);
   tray_applet_ui_set_menu (ta, ta->menu);
   
   /* Check for updates for the first time */
   update_check (ta);
}
