summaryrefslogtreecommitdiff
path: root/modemlights/modem-applet.c
diff options
context:
space:
mode:
Diffstat (limited to 'modemlights/modem-applet.c')
-rw-r--r--modemlights/modem-applet.c1080
1 files changed, 1080 insertions, 0 deletions
diff --git a/modemlights/modem-applet.c b/modemlights/modem-applet.c
new file mode 100644
index 00000000..1e569bf5
--- /dev/null
+++ b/modemlights/modem-applet.c
@@ -0,0 +1,1080 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 2 -*- */
+/* Copyright (C) 2004 Carlos Garnacho
+ *
+ * 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.
+ *
+ * Authors: Carlos Garnacho Parro <[email protected]>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib/gi18n.h>
+#include <mate-panel-applet.h>
+#include <fcntl.h>
+#ifdef HAVE_PTY_H
+#include <pty.h>
+#endif
+#include <sys/poll.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <libxml/tree.h>
+#include <errno.h>
+
+#ifdef __FreeBSD__
+#include <sys/ioctl.h>
+#include <termios.h>
+#include <libutil.h>
+#endif
+
+#include "modem-applet.h"
+
+#define MODEM_APPLET_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TYPE_MODEM_APPLET, ModemAppletPrivate))
+#define NETWORK_TOOL "network-admin"
+#define END_OF_REQUEST "<!-- GST: end of request -->\n"
+#define BUF_SIZE 1024
+
+typedef void (*DirectiveCallback) (ModemApplet*, xmlDoc*);
+typedef struct _BackendDirective BackendDirective;
+typedef struct _ModemAppletPrivate ModemAppletPrivate;
+
+struct _ModemAppletPrivate
+{
+ /* applet UI stuff */
+ GtkBuilder *builder;
+ GtkIconTheme *icon_theme;
+ GdkPixbuf *icon;
+ GtkWidget *image;
+ GtkActionGroup *action_group;
+
+ /* auth dialog */
+ GtkWidget *auth_dialog;
+ GtkWidget *auth_dialog_label;
+ GtkWidget *auth_dialog_entry;
+
+ /* report window */
+ GtkWidget *report_window;
+ GtkWidget *report_window_image;
+ GtkWidget *report_window_progress;
+
+ guint directives_id;
+ guint progress_id;
+ guint tooltip_id;
+ guint info_id;
+ guint timeout_id;
+
+ /* for communicating with the backend */
+ gint config_id;
+ gint pid;
+ int read_fd;
+ int write_fd;
+ FILE *read_stream;
+ FILE *write_stream;
+ GSList *directives;
+ gboolean directive_running;
+
+ /* interface data */
+ gboolean configured; /* is configured? */
+ gboolean enabled; /* is enabled? */
+ gboolean is_isdn; /* is an isdn device? */
+ gchar *dev; /* device name */
+ gchar *lock_file; /* lock file */
+
+ gboolean has_root;
+};
+
+struct _BackendDirective
+{
+ DirectiveCallback callback;
+ GSList *directive;
+ gboolean show_report;
+};
+
+static void modem_applet_class_init (ModemAppletClass *class);
+static void modem_applet_init (ModemApplet *applet);
+static void modem_applet_finalize (GObject *object);
+
+static gboolean update_tooltip (ModemApplet *applet);
+static gboolean dispatch_directives (ModemApplet *applet);
+static gboolean update_info (ModemApplet *applet);
+
+static void modem_applet_change_size (MatePanelApplet *applet, guint size);
+
+static void modem_applet_change_background (MatePanelApplet *app,
+ MatePanelAppletBackgroundType type,
+ GdkColor *colour,
+ GdkPixmap *pixmap);
+
+static void on_modem_applet_about_clicked (GtkAction *action,
+ ModemApplet *applet);
+static void on_modem_applet_activate (GtkAction *action,
+ ModemApplet *applet);
+static void on_modem_applet_deactivate (GtkAction *action,
+ ModemApplet *applet);
+static void on_modem_applet_properties_clicked (GtkAction *action,
+ ModemApplet *applet);
+static void on_modem_applet_help_clicked (GtkAction *action,
+ ModemApplet *applet);
+
+static void launch_backend (ModemApplet *applet,
+ gboolean root_auth);
+static void shutdown_backend (ModemApplet *applet,
+ gboolean backend_alive,
+ gboolean already_waiting);
+
+static gpointer parent_class;
+
+static const GtkActionEntry menu_actions[] = {
+ { "Activate", GTK_STOCK_EXECUTE, N_("_Activate"),
+ NULL, NULL,
+ G_CALLBACK (on_modem_applet_activate) },
+ { "Deactivate", GTK_STOCK_STOP, N_("_Deactivate"),
+ NULL, NULL,
+ G_CALLBACK (on_modem_applet_deactivate) },
+ { "Properties", GTK_STOCK_PROPERTIES, N_("_Properties"),
+ NULL, NULL,
+ G_CALLBACK (on_modem_applet_properties_clicked) },
+ { "Help", GTK_STOCK_HELP, N_("_Help"),
+ NULL, NULL,
+ G_CALLBACK (on_modem_applet_help_clicked) },
+ { "About", GTK_STOCK_ABOUT, N_("_About"),
+ NULL, NULL,
+ G_CALLBACK (on_modem_applet_about_clicked) }
+};
+
+G_DEFINE_TYPE (ModemApplet, modem_applet, PANEL_TYPE_APPLET)
+
+static void
+modem_applet_class_init (ModemAppletClass *class)
+{
+ GObjectClass *object_class;
+ MatePanelAppletClass *applet_class;
+
+ object_class = G_OBJECT_CLASS (class);
+ applet_class = MATE_PANEL_APPLET_CLASS (class);
+ parent_class = g_type_class_peek_parent (class);
+
+ object_class->finalize = modem_applet_finalize;
+ applet_class->change_size = modem_applet_change_size;
+ applet_class->change_background = modem_applet_change_background;
+
+ g_type_class_add_private (object_class, sizeof (ModemAppletPrivate));
+}
+
+static void
+modem_applet_init (ModemApplet *applet)
+{
+ ModemAppletPrivate *priv;
+ GdkPixbuf *pixbuf;
+
+ g_set_application_name ( _("Modem Monitor"));
+
+ priv = MODEM_APPLET_GET_PRIVATE (applet);
+
+ priv->builder = gtk_builder_new ();
+ gtk_builder_add_from_file (priv->builder, GTK_BUILDERDIR "/modemlights.ui", NULL);
+ priv->icon = NULL;
+ priv->icon_theme = gtk_icon_theme_get_default ();
+ priv->image = gtk_image_new ();
+
+ priv->auth_dialog = GTK_WIDGET (gtk_builder_get_object (priv->builder, "auth_dialog"));
+ priv->auth_dialog_label = GTK_WIDGET (gtk_builder_get_object (priv->builder, "auth_dialog_label"));
+ priv->auth_dialog_entry = GTK_WIDGET (gtk_builder_get_object (priv->builder, "auth_dialog_entry"));
+
+ priv->report_window = GTK_WIDGET (gtk_builder_get_object (priv->builder, "report_window"));
+ priv->report_window_image = GTK_WIDGET (gtk_builder_get_object (priv->builder, "report_window_image"));
+ priv->report_window_progress = GTK_WIDGET (gtk_builder_get_object (priv->builder, "report_window_progress"));
+
+ g_signal_connect (G_OBJECT (priv->report_window), "delete-event",
+ G_CALLBACK (gtk_widget_hide), NULL);
+
+ pixbuf = gtk_icon_theme_load_icon (priv->icon_theme, "mate-modem-monitor-applet", 48, 0, NULL);
+ gtk_image_set_from_pixbuf (GTK_IMAGE (priv->report_window_image), pixbuf);
+ g_object_unref (pixbuf);
+
+ priv->configured = FALSE;
+ priv->enabled = FALSE;
+ priv->dev = NULL;
+ priv->lock_file = NULL;
+
+ priv->has_root = FALSE;
+
+ priv->directives = NULL;
+ priv->directives_id = g_timeout_add (250, (GSourceFunc) dispatch_directives, applet);
+ priv->directive_running = FALSE;
+ priv->tooltip_id = g_timeout_add_seconds (1, (GSourceFunc) update_tooltip, applet);
+
+ launch_backend (applet, FALSE);
+ gtk_container_add (GTK_CONTAINER (applet), priv->image);
+}
+
+static void
+modem_applet_finalize (GObject *object)
+{
+ ModemAppletPrivate *priv = MODEM_APPLET_GET_PRIVATE (object);
+
+ if (priv)
+ {
+ shutdown_backend (MODEM_APPLET (object), TRUE, TRUE);
+
+ gtk_widget_destroy (priv->auth_dialog);
+ gtk_widget_destroy (priv->report_window);
+ g_object_unref (priv->icon);
+ g_object_unref (priv->action_group);
+
+ g_free (priv->dev);
+ g_free (priv->lock_file);
+ }
+
+ if (G_OBJECT_CLASS (parent_class)->finalize)
+ (* G_OBJECT_CLASS (parent_class)->finalize) (object);
+}
+
+static void
+modem_applet_change_size (MatePanelApplet *applet,
+ guint size)
+{
+ ModemAppletPrivate *priv = MODEM_APPLET_GET_PRIVATE (applet);
+
+ if (priv->icon)
+ g_object_unref (priv->icon);
+
+ /* this might be too much overload, maybe should we get just one icon size and scale? */
+ priv->icon = gtk_icon_theme_load_icon (priv->icon_theme,
+ "mate-modem", size, 0, NULL);
+ gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image), priv->icon);
+}
+
+static void
+modem_applet_change_background (MatePanelApplet *app,
+ MatePanelAppletBackgroundType type,
+ GdkColor *colour,
+ GdkPixmap *pixmap)
+{
+ ModemApplet *applet = MODEM_APPLET (app);
+ GtkRcStyle *rc_style;
+ GtkStyle *style;
+
+ /* reset style */
+ gtk_widget_set_style (GTK_WIDGET (applet), NULL);
+ rc_style = gtk_rc_style_new ();
+ gtk_widget_modify_style (GTK_WIDGET (applet), rc_style);
+ g_object_unref (rc_style);
+
+ switch (type)
+ {
+ case PANEL_NO_BACKGROUND:
+ break;
+ case PANEL_COLOR_BACKGROUND:
+ gtk_widget_modify_bg (GTK_WIDGET (applet),
+ GTK_STATE_NORMAL, colour);
+ break;
+ case PANEL_PIXMAP_BACKGROUND:
+ style = gtk_style_copy (GTK_WIDGET (applet)->style);
+
+ if (style->bg_pixmap[GTK_STATE_NORMAL])
+ g_object_unref (style->bg_pixmap[GTK_STATE_NORMAL]);
+
+ style->bg_pixmap[GTK_STATE_NORMAL] = g_object_ref (pixmap);
+ gtk_widget_set_style (GTK_WIDGET (applet), style);
+ g_object_unref (style);
+ break;
+ }
+}
+
+static gboolean
+pulse_progressbar (GtkWidget *progressbar)
+{
+ gtk_progress_bar_pulse (GTK_PROGRESS_BAR (progressbar));
+ return TRUE;
+}
+
+/* XML manipulation functions */
+static xmlNodePtr
+get_root_node (xmlDoc *doc)
+{
+ return xmlDocGetRootElement (doc);
+}
+
+static xmlNodePtr
+find_first_element (xmlNodePtr node, const gchar *name)
+{
+ xmlNodePtr n;
+
+ g_return_val_if_fail (node != NULL, NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ for (n = node->children; n; n = n->next)
+ if (n->name && (strcmp (name, (char *) n->name) == 0))
+ break;
+
+ return n;
+}
+
+static xmlNodePtr
+find_next_element (xmlNodePtr node, const gchar *name)
+{
+ xmlNodePtr n;
+
+ g_return_val_if_fail (node != NULL, NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ for (n = node->next; n; n = n->next)
+ if (n->name && (strcmp (name, (char *) n->name) == 0))
+ break;
+
+ return n;
+}
+
+static guchar *
+element_get_attribute (xmlNodePtr node, const gchar *attribute)
+{
+ xmlAttrPtr a;
+
+ g_return_val_if_fail (node != NULL, NULL);
+ a = node->properties;
+
+ while (a)
+ {
+ if (a->name && (strcmp ((char *) a->name, attribute) == 0))
+ return xmlNodeGetContent (a->children);
+
+ a = a->next;
+ }
+
+ return NULL;
+}
+
+static guchar *
+element_get_child_content (xmlNodePtr node, const gchar *tag)
+{
+ xmlNodePtr child, n;
+
+ child = find_first_element (node, tag);
+ if (!child)
+ return NULL;
+
+ for (n = child->children; n; n = n->next)
+ if (n->type == XML_TEXT_NODE)
+ return xmlNodeGetContent (n);
+
+ return NULL;
+}
+
+static xmlNodePtr
+find_dialup_interface_node (xmlNodePtr root)
+{
+ xmlNodePtr node;
+ gchar *type;
+
+ node = find_first_element (root, "interface");
+
+ while (node)
+ {
+ type = (char *) element_get_attribute (node, "type");
+
+ if (type && (strcmp (type, "modem") == 0 || strcmp (type, "isdn") == 0))
+ {
+ g_free (type);
+ return node;
+ }
+
+ g_free (type);
+ node = find_next_element (node, "interface");
+ }
+
+ return NULL;
+}
+
+/* backend communication functions */
+static gchar *
+compose_directive_string (GSList *directive)
+{
+ GString *dir;
+ gchar *arg, *s, *str;
+ GSList *elem;
+
+ elem = directive;
+ dir = g_string_new ("");
+
+ while (elem)
+ {
+ arg = elem->data;
+
+ for (s = arg; *s; s++)
+ {
+ /* escape needed chars */
+ if ((*s == '\\') ||
+ ((*s == ':') && (* (s + 1) == ':')))
+ g_string_append_c (dir, '\\');
+
+ g_string_append_c (dir, *s);
+ }
+
+ g_string_append (dir, "::");
+ elem = elem->next;
+ }
+
+ g_string_append_c (dir, '\n');
+
+ str = dir->str;
+ g_string_free (dir, FALSE);
+
+ return str;
+}
+
+static void
+poll_backend (ModemAppletPrivate *priv)
+{
+ struct pollfd fd;
+
+ fd.fd = priv->read_fd;
+ fd.events = POLLIN || POLLPRI;
+
+ while (poll (&fd, 1, 100) <= 0)
+ {
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+ }
+}
+
+static xmlDoc*
+read_xml (ModemApplet *applet, gboolean show_report)
+{
+ ModemAppletPrivate *priv = MODEM_APPLET_GET_PRIVATE (applet);
+ gchar buffer[BUF_SIZE], *s;
+ GString *str;
+ xmlDoc *doc = NULL;
+ gboolean backend_alive;
+
+ str = g_string_new ("");
+ backend_alive = (waitpid (priv->pid, NULL, WNOHANG) == 0);
+
+ /* if show_report, create pulse timeout and show window */
+ if (show_report)
+ {
+ priv->progress_id = g_timeout_add (200, (GSourceFunc) pulse_progressbar, priv->report_window_progress);
+ gtk_window_set_screen (GTK_WINDOW (priv->report_window), gtk_widget_get_screen (GTK_WIDGET (applet)));
+ gtk_widget_show (priv->report_window);
+ }
+
+ while (backend_alive && !g_strrstr (str->str, END_OF_REQUEST))
+ {
+ poll_backend (priv);
+ fgets (buffer, BUF_SIZE, priv->read_stream);
+ g_string_append (str, buffer);
+
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+
+ backend_alive = (waitpid (priv->pid, NULL, WNOHANG) == 0);
+ }
+
+ /* if show_report, hide window and so */
+ if (show_report)
+ {
+ g_source_remove (priv->progress_id);
+ priv->progress_id = 0;
+ gtk_widget_hide (priv->report_window);
+ }
+
+ s = str->str;
+
+ while (*s && (*s != '<'))
+ s++;
+
+ if (strcmp (s, END_OF_REQUEST) != 0)
+ doc = xmlParseDoc ((xmlChar *) s);
+
+ g_string_free (str, TRUE);
+
+ return doc;
+}
+
+static void
+queue_directive (ModemApplet *applet,
+ DirectiveCallback callback,
+ gboolean show_report,
+ const gchar *dir,
+ ...)
+{
+ ModemAppletPrivate *priv = MODEM_APPLET_GET_PRIVATE (applet);
+ BackendDirective *directive;
+ GSList *list = NULL;
+ va_list ap;
+ gchar *arg;
+
+ list = g_slist_prepend (list, g_strdup (dir));
+ va_start (ap, dir);
+
+ while ((arg = va_arg (ap, gchar *)) != NULL)
+ list = g_slist_prepend (list, g_strdup (arg));
+
+ va_end (ap);
+ list = g_slist_reverse (list);
+
+ directive = g_new0 (BackendDirective, 1);
+ directive->callback = callback;
+ directive->directive = list;
+ directive->show_report = show_report;
+
+ priv->directives = g_slist_append (priv->directives, directive);
+}
+
+static gboolean
+dispatch_directives (ModemApplet *applet)
+{
+ ModemAppletPrivate *priv = MODEM_APPLET_GET_PRIVATE (applet);
+ BackendDirective *directive;
+ xmlDoc *doc;
+ gchar *dir;
+ GSList *elem;
+
+ if (priv->directive_running)
+ return TRUE;
+
+ priv->directive_running = TRUE;
+ elem = priv->directives;
+
+ while (elem)
+ {
+ directive = elem->data;
+
+ dir = compose_directive_string (directive->directive);
+ fputs (dir, priv->write_stream);
+ g_free (dir);
+
+ doc = read_xml (applet, directive->show_report);
+
+ if (directive->callback)
+ directive->callback (applet, doc);
+
+ if (doc)
+ xmlFreeDoc (doc);
+
+ g_slist_foreach (directive->directive, (GFunc) g_free, NULL);
+ g_slist_free (directive->directive);
+
+ elem = elem->next;
+ }
+
+ g_slist_foreach (priv->directives, (GFunc) g_free, NULL);
+ g_slist_free (priv->directives);
+ priv->directives = NULL;
+ priv->directive_running = FALSE;
+
+ return TRUE;
+}
+
+static void
+shutdown_backend (ModemApplet *applet, gboolean backend_alive, gboolean already_waiting)
+{
+ ModemAppletPrivate *priv = MODEM_APPLET_GET_PRIVATE (applet);
+
+ if (priv->info_id)
+ {
+ g_source_remove (priv->info_id);
+ priv->info_id = 0;
+ }
+
+ if (priv->timeout_id)
+ {
+ g_source_remove (priv->timeout_id);
+ priv->timeout_id = 0;
+ }
+
+ if (priv->tooltip_id)
+ {
+ g_source_remove (priv->tooltip_id);
+ priv->tooltip_id = 0;
+ }
+
+ if (backend_alive)
+ kill (priv->pid, 9);
+
+ if (!already_waiting)
+ {
+ /* don't leave zombies */
+ while (waitpid (priv->pid, NULL, WNOHANG) <= 0)
+ {
+ usleep (2000);
+
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+ }
+ }
+
+ /* close remaining streams and fds */
+ fclose (priv->read_stream);
+ fclose (priv->write_stream);
+ close (priv->read_fd);
+ close (priv->write_fd);
+}
+
+/* functions for extracting the interface information from the XML */
+static void
+update_popup_buttons (ModemApplet *applet)
+{
+ GtkAction *action;
+ ModemAppletPrivate *priv = MODEM_APPLET_GET_PRIVATE (applet);
+
+ action = gtk_action_group_get_action (priv->action_group, "Activate");
+ gtk_action_set_sensitive (action, priv->configured && !priv->enabled);
+
+ action = gtk_action_group_get_action (priv->action_group, "Deactivate");
+ gtk_action_set_sensitive (action, priv->configured && priv->enabled);
+}
+
+static void
+get_interface_data (ModemApplet *applet, xmlNodePtr iface)
+{
+ ModemAppletPrivate *priv = MODEM_APPLET_GET_PRIVATE (applet);
+ xmlNodePtr configuration;
+ gchar *text, *device;
+
+ g_return_if_fail (iface != NULL);
+
+ text = (char *) element_get_child_content (iface, "enabled");
+ priv->enabled = (*text == '1');
+ g_free (text);
+
+ g_free (priv->dev);
+ priv->dev = (char *) element_get_child_content (iface, "dev");
+
+ g_free (priv->lock_file);
+ configuration = find_first_element (iface, "configuration");
+
+ if (configuration)
+ {
+ priv->configured = TRUE;
+ text = (char *) element_get_child_content (configuration, "serial_port");
+
+ if (text)
+ {
+ /* Modem device */
+ device = strrchr (text, '/');
+ priv->lock_file = g_strdup_printf ("/var/lock/LCK..%s", device + 1);
+ g_free (text);
+
+ priv->is_isdn = FALSE;
+ }
+ else
+ {
+ /* isdn device */
+ priv->lock_file = g_strdup ("/var/lock/LCK..capi_0");
+ priv->is_isdn = TRUE;
+ }
+ }
+ else
+ {
+ priv->lock_file = NULL;
+ priv->configured = FALSE;
+ }
+}
+
+static gint
+get_connection_time (const gchar *lock_file)
+{
+ struct stat st;
+
+ if (stat (lock_file, &st) == 0)
+ return (gint) (time (NULL) - st.st_mtime);
+
+ return 0;
+}
+
+static gboolean
+update_tooltip (ModemApplet *applet)
+{
+ ModemAppletPrivate *priv = MODEM_APPLET_GET_PRIVATE (applet);
+ gchar *text;
+ gint t, t1, t2;
+
+ if (priv->enabled)
+ {
+ if (!priv->lock_file)
+ text = g_strdup (_("Connection active, but could not get connection time"));
+ else
+ {
+ t = get_connection_time (priv->lock_file);
+
+ if (t < (60 * 60 * 24))
+ {
+ t1 = t / 3600; /* hours */
+ t2 = (t - (t1 * 3600)) / 60; /* minutes */
+ }
+ else
+ {
+ t1 = t / (3600 * 24); /* days */
+ t2 = (t - (t1 * 3600 * 24)) / 3600; /* hours */
+ }
+
+ text = g_strdup_printf (_("Time connected: %.1d:%.2d"), t1, t2);
+ }
+ }
+ else
+ text = g_strdup (_("Not connected"));
+
+ gtk_widget_set_tooltip_text (GTK_WIDGET (applet), text);
+ g_free (text);
+
+ return TRUE;
+}
+
+static void
+rerun_backend_callback (ModemApplet *applet, xmlDoc *doc)
+{
+ ModemAppletPrivate *priv = MODEM_APPLET_GET_PRIVATE (applet);
+ gchar *text, *password;
+ gint response;
+ gboolean enable;
+
+ shutdown_backend (applet, FALSE, FALSE);
+ launch_backend (applet, TRUE);
+
+ enable = !priv->enabled;
+
+ text = (enable) ?
+ _("To connect to your Internet service provider, you need administrator privileges") :
+ _("To disconnect from your Internet service provider, you need administrator privileges");
+
+ gtk_label_set_text (GTK_LABEL (priv->auth_dialog_label), text);
+ gtk_window_set_screen (GTK_WINDOW (priv->auth_dialog),
+ gtk_widget_get_screen (GTK_WIDGET (applet)));
+
+ gtk_widget_grab_focus (priv->auth_dialog_entry);
+ response = gtk_dialog_run (GTK_DIALOG (priv->auth_dialog));
+ gtk_widget_hide (priv->auth_dialog);
+ password = (gchar *) gtk_entry_get_text (GTK_ENTRY (priv->auth_dialog_entry));
+
+ if (response == GTK_RESPONSE_OK)
+ {
+
+ password = (gchar *) gtk_entry_get_text (GTK_ENTRY (priv->auth_dialog_entry));
+ fputs (password, priv->write_stream);
+ fputs ("\n", priv->write_stream);
+
+ while (fflush (priv->write_stream) != 0);
+
+ queue_directive (applet, NULL, enable,
+ "enable_iface", priv->dev, (enable) ? "1" : "0", NULL);
+ }
+ else
+ {
+ shutdown_backend (applet, TRUE, FALSE);
+ launch_backend (applet, FALSE);
+ }
+
+ /* stab the root password */
+ memset (password, ' ', sizeof (password));
+ gtk_entry_set_text (GTK_ENTRY (priv->auth_dialog_entry), "");
+}
+
+static void
+update_info_callback (ModemApplet *applet, xmlDoc *doc)
+{
+ xmlNodePtr iface;
+
+ if (!doc)
+ return;
+
+ iface = find_dialup_interface_node (get_root_node (doc));
+ if (!iface)
+ return;
+
+ get_interface_data (applet, iface);
+ update_popup_buttons (applet);
+}
+
+static gboolean
+update_info (ModemApplet *applet)
+{
+ queue_directive (applet, update_info_callback,
+ FALSE, "get", NULL);
+ return TRUE;
+}
+
+static gboolean
+check_backend (ModemApplet *applet)
+{
+ ModemAppletPrivate *priv = MODEM_APPLET_GET_PRIVATE (applet);
+ gint status, pid = -1;
+ GtkWidget *dialog;
+
+ pid = waitpid (priv->pid, &status, WNOHANG);
+
+ if (pid != 0)
+ {
+ if (errno == ECHILD || ((WIFEXITED (status)) && (WEXITSTATUS (status)) && (WEXITSTATUS(status) < 255)))
+ {
+ dialog = gtk_message_dialog_new (NULL,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_CLOSE,
+ _("The entered password is invalid"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ _("Check that you have typed it correctly and that "
+ "you haven't activated the \"caps lock\" key"));
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ }
+
+ priv->timeout_id = 0;
+ shutdown_backend (applet, FALSE, TRUE);
+ launch_backend (applet, FALSE);
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+launch_backend (ModemApplet *applet, gboolean root_auth)
+{
+ ModemAppletPrivate *priv = MODEM_APPLET_GET_PRIVATE (applet);
+ gchar *non_auth_args[] = { STB_SCRIPTS_DIR "/network-conf", NULL };
+ gchar *auth_args[] = { SU_PATH, "-c", STB_SCRIPTS_DIR "/network-conf", NULL };
+ gchar **args;
+ int p[2];
+
+ pipe (p);
+ priv->pid = forkpty (&priv->write_fd, NULL, NULL, NULL);
+ args = (root_auth) ? auth_args : non_auth_args;
+
+ if (priv->pid < 0)
+ g_warning ("Could not spawn GST backend");
+ else
+ {
+ if (priv->pid == 0)
+ {
+ /* child process */
+ unsetenv("LC_ALL");
+ unsetenv("LC_MESSAGES");
+ unsetenv("LANG");
+ unsetenv("LANGUAGE");
+
+ dup2 (p[1], 1);
+ dup2 (p[1], 2);
+ close (p[0]);
+
+ execv (args[0], args);
+ exit (255);
+ }
+ else
+ {
+ close (p[1]);
+
+ priv->read_fd = p[0];
+ priv->timeout_id = g_timeout_add_seconds (1, (GSourceFunc) check_backend, applet);
+ priv->info_id = g_timeout_add_seconds (3, (GSourceFunc) update_info, applet);
+ priv->read_stream = fdopen (priv->read_fd, "r");
+ priv->write_stream = fdopen (priv->write_fd, "w");
+ priv->has_root = root_auth;
+
+ setvbuf (priv->read_stream, NULL, _IONBF, 0);
+ fcntl (priv->read_fd, F_SETFL, 0);
+ }
+ }
+}
+
+static gboolean
+launch_config_tool (GdkScreen *screen, gboolean is_isdn)
+{
+ gchar *argv[4], *application;
+ gboolean ret;
+
+ application = g_find_program_in_path (NETWORK_TOOL);
+
+ if (!application)
+ return FALSE;
+
+ argv[0] = application;
+ argv[1] = "--configure-type";
+ argv[2] = (is_isdn) ? "isdn" : "modem";
+ argv[3] = NULL;
+
+ ret = gdk_spawn_on_screen (screen, NULL, argv, NULL, 0,
+ NULL, NULL, NULL, NULL);
+ g_free (application);
+ return ret;
+}
+
+static void
+toggle_interface_non_root (ModemApplet *applet, gboolean enable)
+{
+ queue_directive (applet, rerun_backend_callback,
+ FALSE, "end", NULL);
+}
+
+static void
+toggle_interface_root (ModemApplet *applet, gboolean enable)
+{
+ ModemAppletPrivate *priv = MODEM_APPLET_GET_PRIVATE (applet);
+ GtkWidget *dialog;
+ gchar *text;
+
+ text = (enable) ?
+ _("Do you want to connect?") :
+ _("Do you want to disconnect?");
+
+ dialog = gtk_message_dialog_new (NULL,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_NONE,
+ text);
+ gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ (enable) ? _("C_onnect") : _("_Disconnect"),
+ GTK_RESPONSE_OK, NULL);
+ gtk_window_set_screen (GTK_WINDOW (dialog),
+ gtk_widget_get_screen (GTK_WIDGET (applet)));
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK)
+ queue_directive (applet, NULL, enable,
+ "enable_iface", priv->dev, (enable) ? "1" : "0", NULL);
+
+ gtk_widget_destroy (dialog);
+}
+
+static void
+toggle_interface (ModemApplet *applet, gboolean enable)
+{
+ ModemAppletPrivate *priv = MODEM_APPLET_GET_PRIVATE (applet);
+
+ if (priv->has_root)
+ toggle_interface_root (applet, enable);
+ else
+ toggle_interface_non_root (applet, enable);
+}
+
+static void
+on_modem_applet_activate (GtkAction *action,
+ ModemApplet *applet)
+{
+ toggle_interface (applet, TRUE);
+}
+
+static void
+on_modem_applet_deactivate (GtkAction *action,
+ ModemApplet *applet)
+{
+ toggle_interface (applet, FALSE);
+}
+
+static void
+on_modem_applet_properties_clicked (GtkAction *action,
+ ModemApplet *applet)
+{
+ ModemAppletPrivate *priv = MODEM_APPLET_GET_PRIVATE (applet);
+ GdkScreen *screen;
+ GtkWidget *dialog;
+
+ screen = gtk_widget_get_screen (GTK_WIDGET (applet));
+
+ if (!launch_config_tool (screen, priv->is_isdn))
+ {
+ dialog = gtk_message_dialog_new (NULL,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ _("Could not launch network configuration tool"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ _("Check that it's installed in the correct path "
+ "and that it has the correct permissions"));
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ }
+}
+
+static void
+on_modem_applet_about_clicked (GtkAction *action,
+ ModemApplet *applet)
+{
+ const gchar *authors[] = {
+ "Carlos Garnacho Parro <[email protected]>",
+ NULL
+ };
+/*
+ const gchar *documenters[] = {
+ NULL
+ };
+*/
+ gtk_show_about_dialog (NULL,
+ "version", VERSION,
+ "copyright", "Copyright \xC2\xA9 2004 Free Software Foundation. Inc.",
+ "comments", _("Applet for activating and monitoring a dial-up network connection."),
+ "authors", authors,
+ /* "documenters", documenters, */
+ "translator-credits", _("translator-credits"),
+ "logo_icon_name", "mate-modem-monitor-applet",
+ NULL);
+}
+
+static void
+on_modem_applet_help_clicked (GtkAction *action,
+ ModemApplet *applet)
+{
+ gtk_show_uri (gtk_widget_get_screen (GTK_WIDGET (applet)),
+ "ghelp:modemlights",
+ gtk_get_current_event_time (),
+ NULL);
+}
+
+static gboolean
+modem_applet_fill (ModemApplet *applet)
+{
+ ModemAppletPrivate *priv = MODEM_APPLET_GET_PRIVATE (applet);
+ gchar *ui_path;
+
+ g_return_val_if_fail (PANEL_IS_APPLET (applet), FALSE);
+
+ gtk_widget_show_all (GTK_WIDGET (applet));
+
+ priv->action_group = gtk_action_group_new ("ModemLights Applet Actions");
+ gtk_action_group_set_translation_domain (priv->action_group, GETTEXT_PACKAGE);
+ gtk_action_group_add_actions (priv->action_group,
+ menu_actions,
+ G_N_ELEMENTS (menu_actions),
+ applet);
+ update_popup_buttons (applet);
+ ui_path = g_build_filename (MODEM_MENU_UI_DIR, "modem-applet-menu.xml", NULL);
+ mate_panel_applet_setup_menu_from_file (MATE_PANEL_APPLET (applet),
+ ui_path, priv->action_group);
+ g_free (ui_path);
+
+ return TRUE;
+}
+
+static gboolean
+modem_applet_factory (MatePanelApplet *applet,
+ const gchar *iid,
+ gpointer data)
+{
+ gboolean retval = FALSE;
+
+ if (!strcmp (iid, "ModemLightsApplet"))
+ retval = modem_applet_fill (MODEM_APPLET (applet));
+
+ return retval;
+}
+
+MATE_PANEL_APPLET_OUT_PROCESS_FACTORY ("ModemAppletFactory",
+ TYPE_MODEM_APPLET,
+ "modem",
+ modem_applet_factory,
+ NULL)