/* Krb5 Auth Applet -- Acquire and release kerberos tickets * * (C) 2008,2009,2010 Guido Guenther * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "config.h" #include #include "ka-applet-priv.h" #include "ka-dialog.h" #include "ka-gconf-tools.h" #include "ka-gconf.h" #include "ka-tools.h" #include "ka-tickets.h" #include "ka-plugin-loader.h" #include "ka-closures.h" #include #define NOTIFY_SECONDS 300 enum ka_icon { inv_icon = 0, exp_icon, val_icon, }; enum { KA_PROP_0 = 0, KA_PROP_PRINCIPAL, KA_PROP_PK_USERID, KA_PROP_PK_ANCHORS, KA_PROP_PW_PROMPT_MINS, KA_PROP_TGT_FORWARDABLE, KA_PROP_TGT_PROXIABLE, KA_PROP_TGT_RENEWABLE, }; struct _KaApplet { GObject parent; KaAppletPrivate *priv; }; struct _KaAppletClass { GObjectClass parent; guint signals[KA_SIGNAL_COUNT]; }; G_DEFINE_TYPE (KaApplet, ka_applet, G_TYPE_OBJECT); struct _KaAppletPrivate { GtkBuilder *uixml; GtkStatusIcon *tray_icon; /* the tray icon */ GtkWidget *context_menu; /* the tray icon's context menu */ const char *icons[3]; /* for invalid, expiring and valid tickts */ gboolean ns_persistence; /* does the notification server support persistence */ KaPwDialog *pwdialog; /* the password dialog */ int pw_prompt_secs; /* when to start prompting for a password */ KaPluginLoader *loader; /* Plugin loader */ NotifyNotification *notification; /* notification messages */ char *krb_msg; /* Additional banner delivered by Kerberos */ const char *notify_gconf_key; /* disable notification gconf key */ char *principal; /* the principal to request */ gboolean renewable; /* credentials renewable? */ char *pk_userid; /* "userid" for pkint */ char *pk_anchors; /* trust anchors for pkint */ gboolean tgt_forwardable; /* request a forwardable ticket */ gboolean tgt_renewable; /* request a renewable ticket */ gboolean tgt_proxiable; /* request a proxiable ticket */ GConfClient *gconf; /* gconf client */ }; static void ka_close_notification (KaApplet *self); static void ka_applet_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { KaApplet *self = KA_APPLET (object); switch (property_id) { case KA_PROP_PRINCIPAL: g_free (self->priv->principal); self->priv->principal = g_value_dup_string (value); KA_DEBUG ("%s: %s", pspec->name, self->priv->principal); break; case KA_PROP_PK_USERID: g_free (self->priv->pk_userid); self->priv->pk_userid = g_value_dup_string (value); KA_DEBUG ("%s: %s", pspec->name, self->priv->pk_userid); break; case KA_PROP_PK_ANCHORS: g_free (self->priv->pk_anchors); self->priv->pk_anchors = g_value_dup_string (value); KA_DEBUG ("%s: %s", pspec->name, self->priv->pk_anchors); break; case KA_PROP_PW_PROMPT_MINS: self->priv->pw_prompt_secs = g_value_get_uint (value) * 60; KA_DEBUG ("%s: %d", pspec->name, self->priv->pw_prompt_secs / 60); break; case KA_PROP_TGT_FORWARDABLE: self->priv->tgt_forwardable = g_value_get_boolean (value); KA_DEBUG ("%s: %s", pspec->name, self->priv->tgt_forwardable ? "True" : "False"); break; case KA_PROP_TGT_PROXIABLE: self->priv->tgt_proxiable = g_value_get_boolean (value); KA_DEBUG ("%s: %s", pspec->name, self->priv->tgt_proxiable ? "True" : "False"); break; case KA_PROP_TGT_RENEWABLE: self->priv->tgt_renewable = g_value_get_boolean (value); KA_DEBUG ("%s: %s", pspec->name, self->priv->tgt_renewable ? "True" : "False"); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void ka_applet_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { KaApplet *self = KA_APPLET (object); switch (property_id) { case KA_PROP_PRINCIPAL: g_value_set_string (value, self->priv->principal); break; case KA_PROP_PK_USERID: g_value_set_string (value, self->priv->pk_userid); break; case KA_PROP_PK_ANCHORS: g_value_set_string (value, self->priv->pk_anchors); break; case KA_PROP_PW_PROMPT_MINS: g_value_set_uint (value, self->priv->pw_prompt_secs / 60); break; case KA_PROP_TGT_FORWARDABLE: g_value_set_boolean (value, self->priv->tgt_forwardable); break; case KA_PROP_TGT_PROXIABLE: g_value_set_boolean (value, self->priv->tgt_proxiable); break; case KA_PROP_TGT_RENEWABLE: g_value_set_boolean (value, self->priv->tgt_renewable); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void ka_applet_dispose (GObject *object) { KaApplet *applet = KA_APPLET (object); GObjectClass *parent_class = G_OBJECT_CLASS (ka_applet_parent_class); ka_close_notification (applet); if (applet->priv->tray_icon) { g_object_unref (applet->priv->tray_icon); applet->priv->tray_icon = NULL; } if (applet->priv->pwdialog) { g_object_unref (applet->priv->pwdialog); applet->priv->pwdialog = NULL; } if (applet->priv->uixml) { g_object_unref (applet->priv->uixml); applet->priv->uixml = NULL; } if (applet->priv->loader) { g_object_unref (applet->priv->loader); applet->priv->loader = NULL; } if (parent_class->dispose != NULL) parent_class->dispose (object); } static void ka_applet_finalize (GObject *object) { KaApplet *applet = KA_APPLET (object); GObjectClass *parent_class = G_OBJECT_CLASS (ka_applet_parent_class); g_free (applet->priv->principal); g_free (applet->priv->pk_userid); g_free (applet->priv->pk_anchors); g_free (applet->priv->krb_msg); /* no need to free applet->priv */ if (parent_class->finalize != NULL) parent_class->finalize (object); } static void ka_applet_init (KaApplet *applet) { applet->priv = G_TYPE_INSTANCE_GET_PRIVATE (applet, KA_TYPE_APPLET, KaAppletPrivate); } static void ka_applet_class_init (KaAppletClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GParamSpec *pspec; const gchar *signalNames[KA_SIGNAL_COUNT] = { "krb-tgt-acquired", "krb-tgt-renewed", "krb-tgt-expired" }; int i; object_class->dispose = ka_applet_dispose; object_class->finalize = ka_applet_finalize; g_type_class_add_private (klass, sizeof (KaAppletPrivate)); object_class->set_property = ka_applet_set_property; object_class->get_property = ka_applet_get_property; pspec = g_param_spec_string ("principal", "Principal", "Get/Set Kerberos principal", "", G_PARAM_CONSTRUCT | G_PARAM_READWRITE); g_object_class_install_property (object_class, KA_PROP_PRINCIPAL, pspec); pspec = g_param_spec_string ("pk-userid", "PKinit identifier", "Get/Set Pkinit identifier", "", G_PARAM_CONSTRUCT | G_PARAM_READWRITE); g_object_class_install_property (object_class, KA_PROP_PK_USERID, pspec); pspec = g_param_spec_string ("pk-anchors", "PKinit trust anchors", "Get/Set Pkinit trust anchors", "", G_PARAM_CONSTRUCT | G_PARAM_READWRITE); g_object_class_install_property (object_class, KA_PROP_PK_ANCHORS, pspec); pspec = g_param_spec_uint ("pw-prompt-mins", "Password prompting interval", "Password prompting interval in minutes", 0, G_MAXUINT, MINUTES_BEFORE_PROMPTING, G_PARAM_CONSTRUCT | G_PARAM_READWRITE); g_object_class_install_property (object_class, KA_PROP_PW_PROMPT_MINS, pspec); pspec = g_param_spec_boolean ("tgt-forwardable", "Forwardable ticket", "wether to request forwardable tickets", FALSE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE); g_object_class_install_property (object_class, KA_PROP_TGT_FORWARDABLE, pspec); pspec = g_param_spec_boolean ("tgt-proxiable", "Proxiable ticket", "wether to request proxiable tickets", FALSE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE); g_object_class_install_property (object_class, KA_PROP_TGT_PROXIABLE, pspec); pspec = g_param_spec_boolean ("tgt-renewable", "Renewable ticket", "wether to request renewable tickets", FALSE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE); g_object_class_install_property (object_class, KA_PROP_TGT_RENEWABLE, pspec); for (i = 0; i < KA_SIGNAL_COUNT; i++) { guint signalId; signalId = g_signal_new (signalNames[i], G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, ka_closure_VOID__STRING_UINT, G_TYPE_NONE, 2, /* number of parameters */ G_TYPE_STRING, G_TYPE_UINT); klass->signals[i] = signalId; } } static KaApplet * ka_applet_new (void) { return g_object_new (KA_TYPE_APPLET, NULL); } /* determine the new tooltip text */ static char * ka_applet_tooltip_text (int remaining) { int hours, minutes; gchar *tooltip_text; if (remaining > 0) { if (remaining >= 3600) { hours = remaining / 3600; minutes = (remaining % 3600) / 60; /* Translators: First number is hours, second number is minutes */ tooltip_text = g_strdup_printf (_("Your credentials expire in %.2d:%.2dh"), hours, minutes); } else { minutes = remaining / 60; tooltip_text = g_strdup_printf (ngettext ("Your credentials expire in %d minute", "Your credentials expire in %d minutes", minutes), minutes); } } else tooltip_text = g_strdup (_("Your credentials have expired")); return tooltip_text; } /* determine the current icon */ static const char * ka_applet_select_icon (KaApplet *applet, int remaining) { enum ka_icon status_icon = inv_icon; if (remaining > 0) { if (remaining < applet->priv->pw_prompt_secs && !applet->priv->renewable) status_icon = exp_icon; else status_icon = val_icon; } return applet->priv->icons[status_icon]; } static gboolean ka_tray_icon_is_embedded (KaApplet *self) { if (self->priv->tray_icon && gtk_status_icon_is_embedded (self->priv->tray_icon)) return TRUE; else return FALSE; } static gboolean ka_show_notification (KaApplet *applet) { /* wait for the panel to be settled before showing a bubble */ if (applet->priv->ns_persistence || ka_tray_icon_is_embedded (applet)) { GError *error = NULL; gboolean ret; ret = notify_notification_show (applet->priv->notification, &error); if (!ret) { g_assert (error); g_assert (error->message); g_warning ("Failed to show notification: %s", error->message); g_clear_error (&error); } } else { g_timeout_add_seconds (5, (GSourceFunc) ka_show_notification, applet); } return FALSE; } /* Callback to handle disabling of notification */ static void ka_notify_disable_action_cb (NotifyNotification *notification G_GNUC_UNUSED, gchar *action, gpointer user_data) { KaApplet *self = KA_APPLET (user_data); if (strcmp (action, "dont-show-again") == 0) { KA_DEBUG ("turning of notification %s", self->priv->notify_gconf_key); ka_gconf_set_bool (self->priv->gconf, self->priv->notify_gconf_key, FALSE); self->priv->notify_gconf_key = NULL; } else { g_warning ("unkonwn action for callback"); } } /* Callback to handle ticket related actions */ static void ka_notify_ticket_action_cb (NotifyNotification *notification G_GNUC_UNUSED, gchar *action, gpointer user_data) { KaApplet *self = KA_APPLET (user_data); g_return_if_fail (self != NULL); if (strcmp (action, "ka-acquire-tgt") == 0) { KA_DEBUG ("Getting new tgt"); ka_grab_credentials (self); } else if (strcmp (action, "ka-remove-ccache") == 0) { KA_DEBUG ("Removing ccache"); ka_destroy_ccache (self); } else if (strcmp (action, "ka-list-tickets") == 0) { KA_DEBUG ("Listing tickets"); ka_tickets_dialog_run (); } else { g_warning ("unkonwn action for callback"); } } static void ka_close_notification (KaApplet *self) { GError *error = NULL; if (self->priv->notification != NULL) { if (!notify_notification_close (self->priv->notification, &error)) { if (error) g_warning ("Cannot close notification %s", error->message); else g_warning ("Cannot close notification"); } g_object_unref (self->priv->notification); g_clear_error (&error); self->priv->notification = NULL; } } static void ka_send_event_notification (KaApplet *self, const char *summary, const char *message, const char *icon, gboolean get_ticket_action) { NotifyNotification *notification; const char *hint; gint timeout; g_return_if_fail (self != NULL); g_return_if_fail (summary != NULL); g_return_if_fail (message != NULL); if (!notify_is_initted ()) notify_init (KA_NAME); if (self->priv->notification) { notification = self->priv->notification; notify_notification_update (notification, summary, message, icon); } else { notification = self->priv->notification = #if HAVE_NOTIFY_NOTIFICATION_NEW_WITH_STATUS_ICON notify_notification_new_with_status_icon (summary, message, icon, self->priv->tray_icon); #else notify_notification_new (summary, message, icon); #endif notify_notification_set_urgency (notification, NOTIFY_URGENCY_NORMAL); } if (self->priv->ns_persistence) { hint = "resident"; timeout = NOTIFY_EXPIRES_NEVER; notify_notification_set_timeout (notification, timeout); notify_notification_clear_hints (notification); #if HAVE_NOTIFY_NOTIFICATION_SET_HINT notify_notification_set_hint (notification, hint, g_variant_new_boolean (TRUE)); #endif } notify_notification_clear_actions(notification); /* Add List Tickets button until we moved this into cc-panl */ if (self->priv->ns_persistence) { notify_notification_add_action (notification, "ka-list-tickets", _("List Tickets"), (NotifyActionCallback) ka_notify_ticket_action_cb, self, NULL); } if (get_ticket_action) { notify_notification_add_action (notification, "ka-acquire-tgt", _("Get Ticket"), (NotifyActionCallback) ka_notify_ticket_action_cb, self, NULL); } else { if (!self->priv->ns_persistence) { notify_notification_add_action (notification, "dont-show-again", _("Don't show me this again"), (NotifyActionCallback) ka_notify_disable_action_cb, self, NULL); } else { notify_notification_add_action (notification, "ka-remove-ccache", _("Remove Credentials Cache"), (NotifyActionCallback) ka_notify_ticket_action_cb, self, NULL); } } ka_show_notification (self); } static void ka_update_tray_icon (KaApplet *self, const char *icon, const char *tooltip) { if (self->priv->tray_icon) { gtk_status_icon_set_from_icon_name (self->priv->tray_icon, icon); gtk_status_icon_set_tooltip_text (self->priv->tray_icon, tooltip); } } /* * update the tray icon's tooltip and icon * and notify listeners about acquired/expiring tickets via signals */ int ka_applet_update_status (KaApplet *applet, krb5_timestamp expiry) { int now = time (0); int remaining = expiry - now; static int last_warn = 0; static gboolean expiry_notified = FALSE; static krb5_timestamp old_expiry = 0; gboolean notify = TRUE; const char *status_icon = ka_applet_select_icon (applet, remaining); char *tooltip_text = ka_applet_tooltip_text (remaining); if (remaining > 0) { if (expiry_notified) { const char* msg; ka_gconf_get_bool (applet->priv->gconf, KA_GCONF_KEY_NOTIFY_VALID, ¬ify); if (notify) { applet->priv->notify_gconf_key = KA_GCONF_KEY_NOTIFY_VALID; if (applet->priv->krb_msg) msg = applet->priv->krb_msg; else msg = _("You've refreshed your Kerberos credentials."); ka_send_event_notification (applet, _("Network credentials valid"), msg, "krb-valid-ticket", FALSE); } ka_applet_signal_emit (applet, KA_SIGNAL_ACQUIRED_TGT, expiry); expiry_notified = FALSE; g_free (applet->priv->krb_msg); applet->priv->krb_msg = NULL; } else { if (remaining < applet->priv->pw_prompt_secs && (now - last_warn) > NOTIFY_SECONDS && !applet->priv->renewable) { ka_gconf_get_bool (applet->priv->gconf, KA_GCONF_KEY_NOTIFY_EXPIRING, ¬ify); if (notify) { applet->priv->notify_gconf_key = KA_GCONF_KEY_NOTIFY_EXPIRING; ka_send_event_notification (applet, _("Network credentials expiring"), tooltip_text, "krb-expiring-ticket", TRUE); } last_warn = now; } /* ticket lifetime got longer e.g. by kinit -R */ if (old_expiry && expiry > old_expiry) ka_applet_signal_emit (applet, KA_SIGNAL_RENEWED_TGT, expiry); } } else { if (!expiry_notified) { ka_gconf_get_bool (applet->priv->gconf, KA_GCONF_KEY_NOTIFY_EXPIRED, ¬ify); if (notify) { applet->priv->notify_gconf_key = KA_GCONF_KEY_NOTIFY_EXPIRED; ka_send_event_notification (applet, _("Network credentials expired"), _("Your Kerberos credentails have expired."), "krb-no-valid-ticket", TRUE); } ka_applet_signal_emit (applet, KA_SIGNAL_EXPIRED_TGT, expiry); expiry_notified = TRUE; last_warn = 0; } } old_expiry = expiry; ka_update_tray_icon(applet, status_icon, tooltip_text); g_free (tooltip_text); return 0; } static void ka_applet_menu_add_separator_item (GtkWidget *menu) { GtkWidget *menu_item; menu_item = gtk_separator_menu_item_new (); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); gtk_widget_show (menu_item); } static void ka_applet_cb_preferences (GtkWidget *menuitem G_GNUC_UNUSED, gpointer user_data G_GNUC_UNUSED) { GError *error = NULL; g_spawn_command_line_async (BIN_DIR G_DIR_SEPARATOR_S "gnome-control-center ka-panel", &error); if (error) { GtkWidget *message_dialog; message_dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("There was an error launching the preferences dialog: %s"), error->message); gtk_window_set_resizable (GTK_WINDOW (message_dialog), FALSE); g_signal_connect (message_dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL); gtk_widget_show (message_dialog); g_clear_error (&error); } } /* Free all resources and quit */ static void ka_applet_cb_quit (GtkMenuItem *menuitem G_GNUC_UNUSED, gpointer user_data) { KaApplet *applet = KA_APPLET (user_data); g_object_unref (applet); gtk_main_quit (); } static void ka_applet_cb_about_dialog (GtkMenuItem *menuitem G_GNUC_UNUSED, gpointer user_data G_GNUC_UNUSED) { const gchar *authors[] = { "Christopher Aillon ", "Jonathan Blandford ", "Colin Walters ", "Guido Günther ", NULL }; gtk_show_about_dialog (NULL, "authors", authors, "version", VERSION, "logo-icon-name", "krb-valid-ticket", "copyright", "Copyright (C) 2004,2005,2006 Red Hat, Inc.,\n" "2008,2009 Guido Günther", "website-label", PACKAGE " website", "website", "https://honk.sigxcpu.org/piki/projects/krb5-auth-dialog/", "license", "GNU General Public License Version 2", /* Translators: add the translators of your language here */ "translator-credits", _("translator-credits"), NULL); } static void ka_applet_cb_show_help (GtkMenuItem *menuitem G_GNUC_UNUSED, gpointer user_data) { KaApplet *applet = KA_APPLET (user_data); ka_show_help (gtk_status_icon_get_screen (applet->priv->tray_icon), NULL, NULL); } static void ka_applet_cb_destroy_ccache (GtkMenuItem *menuitem G_GNUC_UNUSED, gpointer user_data) { KaApplet *applet = KA_APPLET (user_data); ka_destroy_ccache (applet); } static void ka_applet_cb_show_tickets (GtkMenuItem *menuitem G_GNUC_UNUSED, gpointer user_data G_GNUC_UNUSED) { ka_tickets_dialog_run (); } /* The tray icon's context menu */ static gboolean ka_applet_create_context_menu (KaApplet *applet) { GtkWidget *menu; GtkWidget *menu_item; GtkWidget *image; menu = gtk_menu_new (); /* kdestroy */ menu_item = gtk_image_menu_item_new_with_mnemonic (_("Remove Credentials _Cache")); g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (ka_applet_cb_destroy_ccache), applet); image = gtk_image_new_from_stock (GTK_STOCK_CANCEL, GTK_ICON_SIZE_MENU); gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item), image); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); ka_applet_menu_add_separator_item (menu); /* Ticket dialog */ menu_item = gtk_image_menu_item_new_with_mnemonic (_("_List Tickets")); g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (ka_applet_cb_show_tickets), applet); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); /* Preferences */ menu_item = gtk_image_menu_item_new_from_stock (GTK_STOCK_PREFERENCES, NULL); g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (ka_applet_cb_preferences), applet); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); /* About item */ menu_item = gtk_image_menu_item_new_from_stock (GTK_STOCK_HELP, NULL); g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (ka_applet_cb_show_help), applet); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); /* About item */ menu_item = gtk_image_menu_item_new_from_stock (GTK_STOCK_ABOUT, NULL); g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (ka_applet_cb_about_dialog), applet); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); ka_applet_menu_add_separator_item (menu); /* Quit */ menu_item = gtk_image_menu_item_new_from_stock (GTK_STOCK_QUIT, NULL); g_signal_connect (G_OBJECT (menu_item), "activate", G_CALLBACK (ka_applet_cb_quit), applet); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); gtk_widget_show_all (menu); applet->priv->context_menu = menu; return TRUE; } static void ka_tray_icon_on_menu (GtkStatusIcon *status_icon G_GNUC_UNUSED, guint button, guint activate_time, gpointer user_data) { KaApplet *applet = KA_APPLET (user_data); KA_DEBUG ("Trayicon right clicked: %d", applet->priv->pw_prompt_secs); gtk_menu_popup (GTK_MENU (applet->priv->context_menu), NULL, NULL, gtk_status_icon_position_menu, applet->priv->tray_icon, button, activate_time); } static gboolean ka_tray_icon_on_click (GtkStatusIcon *status_icon G_GNUC_UNUSED, gpointer data) { KaApplet *applet = KA_APPLET (data); KA_DEBUG ("Trayicon clicked: %d", applet->priv->pw_prompt_secs); ka_grab_credentials (applet); return TRUE; } static gboolean ka_applet_create_tray_icon (KaApplet *self) { GtkStatusIcon *tray_icon; if (self->priv->ns_persistence) return FALSE; tray_icon = self->priv->tray_icon = gtk_status_icon_new (); g_signal_connect (G_OBJECT (tray_icon), "activate", G_CALLBACK (ka_tray_icon_on_click), self); g_signal_connect (G_OBJECT (tray_icon), "popup-menu", G_CALLBACK (ka_tray_icon_on_menu), self); gtk_status_icon_set_from_icon_name (tray_icon, self->priv->icons[exp_icon]); gtk_status_icon_set_tooltip_text (tray_icon, PACKAGE); gtk_status_icon_set_title (tray_icon, KA_NAME); return TRUE; } static int ka_applet_setup_icons (KaApplet *applet) { /* Add application specific icons to search path */ gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (), DATA_DIR G_DIR_SEPARATOR_S "icons"); applet->priv->icons[val_icon] = "krb-valid-ticket"; applet->priv->icons[exp_icon] = "krb-expiring-ticket"; applet->priv->icons[inv_icon] = "krb-no-valid-ticket"; return TRUE; } guint ka_applet_get_pw_prompt_secs (const KaApplet *applet) { return applet->priv->pw_prompt_secs; } void ka_applet_set_tgt_renewable (KaApplet *applet, gboolean renewable) { applet->priv->renewable = renewable; } gboolean ka_applet_get_tgt_renewable (const KaApplet *applet) { return applet->priv->renewable; } KaPwDialog * ka_applet_get_pwdialog (const KaApplet *applet) { return applet->priv->pwdialog; } GConfClient * ka_applet_get_gconf_client (const KaApplet *self) { return self->priv->gconf; } void ka_applet_set_msg (KaApplet *self, const char *msg) { g_free (self->priv->krb_msg); self->priv->krb_msg = g_strdup (msg); } void ka_applet_signal_emit (KaApplet *this, KaAppletSignalNumber signum, krb5_timestamp expiry) { KaAppletClass *klass = KA_APPLET_GET_CLASS (this); char *princ; princ = ka_unparse_name (); if (!princ) return; g_signal_emit (this, klass->signals[signum], 0, princ, (guint32) expiry); g_free (princ); } static void ka_ns_check_persistence (KaApplet *self) { GList *caps; GList *l; gboolean is_autostart = g_getenv("DESKTOP_AUTOSTART_ID") ? TRUE : FALSE; gint seconds = 5; self->priv->ns_persistence = FALSE; do { caps = notify_get_server_caps (); if (caps == NULL) g_warning ("Failed to read server caps"); else { l = g_list_find_custom (caps, "persistence", (GCompareFunc)strcmp); if (l != NULL) { self->priv->ns_persistence = TRUE; KA_DEBUG ("Notification server supports persistence."); } g_list_foreach (caps, (GFunc) g_free, NULL); g_list_free (caps); } /* During session start we have to wait until the shell is fully up * to reliably detect the persistence property (#642666) */ if (is_autostart && !self->priv->ns_persistence) { sleep(1); seconds--; } else break; } while (seconds); } /* create the tray icon applet */ KaApplet * ka_applet_create () { KaApplet *applet = ka_applet_new (); GError *error = NULL; gboolean ret; if (!(ka_applet_setup_icons (applet))) g_error ("Failure to setup icons"); gtk_window_set_default_icon_name (applet->priv->icons[val_icon]); if (!ka_applet_create_context_menu (applet)) g_error ("Failure to create context menu"); ka_ns_check_persistence(applet); ka_applet_create_tray_icon (applet); applet->priv->uixml = gtk_builder_new (); ret = gtk_builder_add_from_file (applet->priv->uixml, KA_DATA_DIR G_DIR_SEPARATOR_S PACKAGE ".ui", &error); if (!ret) { g_assert (error); g_assert (error->message); g_error ("Failed to load UI XML: %s", error->message); } applet->priv->pwdialog = ka_pwdialog_create (applet->priv->uixml); g_return_val_if_fail (applet->priv->pwdialog != NULL, NULL); applet->priv->gconf = ka_gconf_init (applet); g_return_val_if_fail (applet->priv->gconf != NULL, NULL); ka_tickets_dialog_create (applet->priv->uixml); applet->priv->loader = ka_plugin_loader_create (applet); g_return_val_if_fail (applet->priv->loader != NULL, NULL); return applet; } /* * vim:ts:sts=4:sw=4:et: */