summaryrefslogtreecommitdiff
path: root/properties
diff options
context:
space:
mode:
authorGuido Günther <agx@sigxcpu.org>2012-02-08 15:53:42 +0100
committerGuido Günther <agx@sigxcpu.org>2012-02-08 15:53:42 +0100
commit2fc4078bc842efa253f84398fad8e655a3714568 (patch)
treed24372b6c48d98b8f240cd5a2d2f92b81b314f4b /properties
Initial commitv0.0.1
Diffstat (limited to 'properties')
-rw-r--r--properties/Makefile.am34
-rw-r--r--properties/nm-iodine-dialog.ui291
-rw-r--r--properties/nm-iodine.c768
-rw-r--r--properties/nm-iodine.h83
4 files changed, 1176 insertions, 0 deletions
diff --git a/properties/Makefile.am b/properties/Makefile.am
new file mode 100644
index 0000000..30e7529
--- /dev/null
+++ b/properties/Makefile.am
@@ -0,0 +1,34 @@
+plugindir = $(libdir)/NetworkManager
+plugin_LTLIBRARIES = libnm-iodine-properties.la
+
+libnm_iodine_properties_la_SOURCES = \
+ nm-iodine.c \
+ nm-iodine.h
+
+uidir = $(datadir)/gnome-vpn-properties/iodine
+ui_DATA = nm-iodine-dialog.ui
+
+libnm_iodine_properties_la_CFLAGS = \
+ $(GTK_CFLAGS) \
+ $(GCONF_CFLAGS) \
+ $(NM_CFLAGS) \
+ -DICONDIR=\""$(datadir)/pixmaps"\" \
+ -DUIDIR=\""$(uidir)"\" \
+ -DG_DISABLE_DEPRECATED \
+ -DGDK_DISABLE_DEPRECATED \
+ -DGNOME_DISABLE_DEPRECATED \
+ -DGNOMELOCALEDIR=\"$(datadir)/locale\" \
+ -DVERSION=\"$(VERSION)\"
+
+libnm_iodine_properties_la_LIBADD = \
+ $(GTK_LIBS) \
+ $(GCONF_LIBS) \
+ $(NM_LIBS)
+
+libnm_iodine_properties_la_LDFLAGS = \
+ -avoid-version
+
+CLEANFILES = *.bak *~
+
+EXTRA_DIST = \
+ $(ui_DATA)
diff --git a/properties/nm-iodine-dialog.ui b/properties/nm-iodine-dialog.ui
new file mode 100644
index 0000000..f362c6c
--- /dev/null
+++ b/properties/nm-iodine-dialog.ui
@@ -0,0 +1,291 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 2.6 -->
+ <object class="GtkListStore" id="pass_type_model">
+ <columns>
+ <!-- column-name gchararray -->
+ <column type="gchararray"/>
+ </columns>
+ <data>
+ <row>
+ <col id="0" translatable="yes">Saved</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Always ask</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Not required</col>
+ </row>
+ </data>
+ </object>
+ <object class="GtkVBox" id="iodine-vbox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">12</property>
+ <property name="spacing">16</property>
+ <child>
+ <object class="GtkVBox" id="vbox8">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label22">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">&lt;b&gt;General&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment8">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkTable" id="table2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">6</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkAlignment" id="alignment2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">1</property>
+ <property name="xscale">0</property>
+ <child>
+ <object class="GtkEntry" id="topdomain_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_focus">True</property>
+ <property name="invisible_char">•</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label23">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Toplevel Domain:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">topdomain_entry</property>
+ </object>
+ <packing>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">&lt;b&gt;Optional&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label28">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Nameserver:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">nameserver_entry</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Password:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">password_entry</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="password_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="visibility">False</property>
+ <property name="invisible_char">●</property>
+ <property name="invisible_char_set">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label29">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Fragment Size:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">fragsize_entry</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="fragsize_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">•</property>
+ <property name="invisible_char_set">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">3</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="nameserver_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">•</property>
+ <property name="invisible_char_set">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="show_passwords_checkbutton">
+ <property name="label" translatable="yes">Show password</property>
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_action_appearance">False</property>
+ <property name="xalign">0</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="pass_type_combo">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="model">pass_type_model</property>
+ <child>
+ <object class="GtkCellRendererText" id="renderer2"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/properties/nm-iodine.c b/properties/nm-iodine.c
new file mode 100644
index 0000000..b1e7537
--- /dev/null
+++ b/properties/nm-iodine.c
@@ -0,0 +1,768 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * GNOME UI dialogs for configuring iodine VPN connections
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright © 2012 Guido Günther <agx@sigxcpu.org>
+ *
+ * Based on network-manager-{openconnect,pptp}
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <glib/gi18n-lib.h>
+#include <string.h>
+#include <gtk/gtk.h>
+
+#define NM_VPN_API_SUBJECT_TO_CHANGE
+
+#include <nm-vpn-plugin-ui-interface.h>
+#include <nm-setting-vpn.h>
+#include <nm-setting-connection.h>
+#include <nm-setting-ip4-config.h>
+
+#include "../src/nm-iodine-service.h"
+#include "nm-iodine.h"
+
+#define IODINE_PLUGIN_NAME _("Iodine DNS Tunnel")
+#define IODINE_PLUGIN_DESC _("Tunnel connections via DNS.")
+#define IODINE_PLUGIN_SERVICE NM_DBUS_SERVICE_IODINE
+
+#define PW_TYPE_SAVE 0
+#define PW_TYPE_ASK 1
+#define PW_TYPE_UNUSED 2
+
+/************** plugin class **************/
+
+static void iodine_plugin_ui_interface_init (NMVpnPluginUiInterface
+ *iface_class);
+
+G_DEFINE_TYPE_EXTENDED (IodinePluginUi, iodine_plugin_ui, G_TYPE_OBJECT, 0,
+ G_IMPLEMENT_INTERFACE (NM_TYPE_VPN_PLUGIN_UI_INTERFACE,
+ iodine_plugin_ui_interface_init))
+
+/************** UI widget class **************/
+
+static void iodine_plugin_ui_widget_interface_init (NMVpnPluginUiWidgetInterface
+ *iface_class);
+
+G_DEFINE_TYPE_EXTENDED (IodinePluginUiWidget, iodine_plugin_ui_widget,G_TYPE_OBJECT, 0,
+ G_IMPLEMENT_INTERFACE (NM_TYPE_VPN_PLUGIN_UI_WIDGET_INTERFACE,
+ iodine_plugin_ui_widget_interface_init))
+
+#define IODINE_PLUGIN_UI_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), IODINE_TYPE_PLUGIN_UI_WIDGET, IodinePluginUiWidgetPrivate))
+
+typedef struct {
+ GtkBuilder *builder;
+ GtkWidget *widget;
+ GtkSizeGroup *group;
+ gboolean window_added;
+} IodinePluginUiWidgetPrivate;
+
+static NMConnection *
+import (NMVpnPluginUiInterface *iface, const char *path, GError **error)
+{
+ NMConnection *connection;
+ NMSettingConnection *s_con;
+ NMSettingVPN *s_vpn;
+ NMSettingIP4Config *s_ip4;
+ GKeyFile *keyfile;
+ GKeyFileFlags flags;
+ const char *buf;
+
+ keyfile = g_key_file_new ();
+ flags = G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS;
+
+ if (!g_key_file_load_from_file (keyfile, path, flags, error)) {
+ g_set_error (error,
+ 0,
+ 0,
+ "does not look like a %s VPN connection (parse failed)",
+ IODINE_PLUGIN_NAME);
+ return NULL;
+ }
+
+ connection = nm_connection_new ();
+ s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
+ nm_connection_add_setting (connection, NM_SETTING (s_con));
+
+ s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ());
+ g_object_set (s_vpn,
+ NM_SETTING_VPN_SERVICE_TYPE,
+ NM_DBUS_SERVICE_IODINE,
+ NULL);
+ nm_connection_add_setting (connection, NM_SETTING (s_vpn));
+
+ s_ip4 = NM_SETTING_IP4_CONFIG (nm_setting_ip4_config_new ());
+ nm_connection_add_setting (connection, NM_SETTING (s_ip4));
+
+ /* top level domain */
+ buf = g_key_file_get_string (keyfile, "iodine", "topdomain", NULL);
+ if (buf) {
+ nm_setting_vpn_add_data_item (s_vpn, NM_IODINE_KEY_TOPDOMAIN, buf);
+ } else {
+ g_set_error (error,
+ 0,
+ 0,
+ "does not look like a %s VPN connection "
+ "(no top level domain)",
+ IODINE_PLUGIN_NAME);
+ g_object_unref (connection);
+ return NULL;
+ }
+
+ /* Optional Settings */
+ /* Description */
+ buf = g_key_file_get_string (keyfile, "iodine", "Description", NULL);
+ if (buf)
+ g_object_set (s_con, NM_SETTING_CONNECTION_ID, buf, NULL);
+
+ /* Name server */
+ buf = g_key_file_get_string (keyfile, "iodine", "Nameserver", NULL);
+ if (buf)
+ nm_setting_vpn_add_data_item (s_vpn, NM_IODINE_KEY_NAMESERVER, buf);
+
+ /* Fragment size */
+ buf = g_key_file_get_string (keyfile, "iodine", "Fragsize", NULL);
+ if (buf)
+ nm_setting_vpn_add_data_item (s_vpn, NM_IODINE_KEY_FRAGSIZE, "yes");
+
+ return connection;
+}
+
+static gboolean
+export (NMVpnPluginUiInterface *iface,
+ const char *path,
+ NMConnection *connection,
+ GError **error)
+{
+ NMSettingConnection *s_con;
+ NMSettingVPN *s_vpn;
+ const char *value;
+ const char *topdomain = NULL;
+ const char *nameserver = NULL;
+ const char *fragsize = NULL;
+ gboolean success = FALSE;
+ FILE *f;
+
+ f = fopen (path, "w");
+ if (!f) {
+ g_set_error (error, 0, 0, "could not open file for writing");
+ return FALSE;
+ }
+
+ s_con = NM_SETTING_CONNECTION (nm_connection_get_setting
+ (connection, NM_TYPE_SETTING_CONNECTION));
+
+ s_vpn = (NMSettingVPN *) nm_connection_get_setting (connection,
+ NM_TYPE_SETTING_VPN);
+
+ value = nm_setting_vpn_get_data_item (s_vpn, NM_IODINE_KEY_TOPDOMAIN);
+ if (value && strlen (value))
+ topdomain = value;
+ else {
+ g_set_error (error, 0, 0,
+ "connection was incomplete (missing top level domain)");
+ goto done;
+ }
+
+ value = nm_setting_vpn_get_data_item (s_vpn, NM_IODINE_KEY_NAMESERVER);
+ if (value && strlen (value))
+ nameserver = value;
+
+ value = nm_setting_vpn_get_data_item (s_vpn, NM_IODINE_KEY_FRAGSIZE);
+ if (value && strlen (value))
+ fragsize = value;
+
+ fprintf (f,
+ "[iodine]\n"
+ "Description=%s\n"
+ "Topdomain=%s\n"
+ "Nameserver=%s\n"
+ "Fragsize=%s\n",
+ /* Description */ nm_setting_connection_get_id (s_con),
+ /* Topdomain */ topdomain,
+ /* Nameserver */ nameserver,
+ /* Fragsize */ fragsize);
+
+ success = TRUE;
+
+done:
+ fclose (f);
+ return success;
+}
+
+GQuark
+iodine_plugin_ui_error_quark (void)
+{
+ static GQuark error_quark = 0;
+
+ if (G_UNLIKELY (error_quark == 0))
+ error_quark = g_quark_from_static_string ("iodine-plugin-ui-error-quark");
+
+ return error_quark;
+}
+
+/* This should really be standard. */
+#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
+
+GType
+iodine_plugin_ui_error_get_type (void)
+{
+ static GType etype = 0;
+
+ if (etype == 0) {
+ static const GEnumValue values[] = {
+ /* Unknown error. */
+ ENUM_ENTRY (IODINE_PLUGIN_UI_ERROR_UNKNOWN,
+ "UnknownError"),
+ /* The specified property was invalid. */
+ ENUM_ENTRY (IODINE_PLUGIN_UI_ERROR_INVALID_PROPERTY,
+ "InvalidProperty"),
+ /* The specified property was missing and is required. */
+ ENUM_ENTRY (IODINE_PLUGIN_UI_ERROR_MISSING_PROPERTY,
+ "MissingProperty"),
+ { 0, 0, 0 }
+ };
+ etype = g_enum_register_static ("IodinePluginUiError", values);
+ }
+ return etype;
+}
+
+static gboolean
+check_validity (IodinePluginUiWidget *self, GError **error)
+{
+ IodinePluginUiWidgetPrivate *priv = \
+ IODINE_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
+ GtkWidget *widget;
+ const char *str;
+
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
+ "topdomain_entry"));
+ str = gtk_entry_get_text (GTK_ENTRY (widget));
+ if (!str || !strlen (str)) {
+ g_set_error (error,
+ IODINE_PLUGIN_UI_ERROR,
+ IODINE_PLUGIN_UI_ERROR_INVALID_PROPERTY,
+ NM_IODINE_KEY_TOPDOMAIN);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+stuff_changed_cb (GtkWidget *widget, gpointer user_data)
+{
+ g_signal_emit_by_name (IODINE_PLUGIN_UI_WIDGET (user_data), "changed");
+}
+
+static void
+setup_password_widget (IodinePluginUiWidget *self,
+ const char *entry_name,
+ NMSettingVPN *s_vpn,
+ const char *secret_name)
+{
+ IodinePluginUiWidgetPrivate *priv = \
+ IODINE_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
+
+ NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE;
+ GtkWidget *widget;
+ const char *value;
+
+ /* Default to agent-owned for new connections */
+ if (s_vpn == NULL)
+ secret_flags = NM_SETTING_SECRET_FLAG_AGENT_OWNED;
+
+ widget = (GtkWidget *) gtk_builder_get_object (priv->builder, entry_name);
+ g_assert (widget);
+ gtk_size_group_add_widget (priv->group, widget);
+
+ if (s_vpn) {
+ value = nm_setting_vpn_get_secret (s_vpn, secret_name);
+ gtk_entry_set_text (GTK_ENTRY (widget), value ? value : "");
+ nm_setting_get_secret_flags (NM_SETTING (s_vpn),
+ secret_name,
+ &secret_flags,
+ NULL);
+ }
+
+ secret_flags &= ~(NM_SETTING_SECRET_FLAG_NOT_SAVED |
+ NM_SETTING_SECRET_FLAG_NOT_REQUIRED);
+ g_object_set_data (G_OBJECT (widget),
+ "flags",
+ GUINT_TO_POINTER (secret_flags));
+
+ g_signal_connect (widget, "changed", G_CALLBACK (stuff_changed_cb), self);
+}
+
+static void
+show_toggled_cb (GtkCheckButton *button, IodinePluginUiWidget *self)
+{
+ IodinePluginUiWidgetPrivate *priv = \
+ IODINE_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
+ GtkWidget *widget;
+ gboolean visible;
+
+ visible = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
+
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
+ "password_entry"));
+ g_assert (widget);
+ gtk_entry_set_visibility (GTK_ENTRY (widget), visible);
+}
+
+static void
+pw_type_combo_changed_cb (GtkWidget *combo, gpointer user_data)
+{
+ IodinePluginUiWidget *self = IODINE_PLUGIN_UI_WIDGET (user_data);
+ IodinePluginUiWidgetPrivate *priv = \
+ IODINE_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
+ GtkWidget *entry;
+
+ entry = GTK_WIDGET (gtk_builder_get_object (priv->builder,
+ "password_entry"));
+ g_assert (entry);
+
+ /* If the user chose "Not required", desensitize and clear the correct
+ * password entry.
+ */
+ switch (gtk_combo_box_get_active (GTK_COMBO_BOX (combo))) {
+ case PW_TYPE_ASK:
+ case PW_TYPE_UNUSED:
+ gtk_entry_set_text (GTK_ENTRY (entry), "");
+ gtk_widget_set_sensitive (entry, FALSE);
+ break;
+ default:
+ gtk_widget_set_sensitive (entry, TRUE);
+ break;
+ }
+
+ stuff_changed_cb (combo, self);
+}
+
+static void
+init_one_pw_combo (IodinePluginUiWidget *self,
+ NMSettingVPN *s_vpn,
+ const char *combo_name,
+ const char *secret_key,
+ const char *entry_name)
+{
+ IodinePluginUiWidgetPrivate *priv = \
+ IODINE_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
+ int active = -1;
+ GtkWidget *widget;
+ GtkListStore *store;
+ const char *value = NULL;
+ guint32 default_idx = 1;
+ NMSettingSecretFlags pw_flags = NM_SETTING_SECRET_FLAG_NONE;
+
+ /* If there's already a password and the password type can't be found in
+ * the VPN settings, default to saving it. Otherwise, always ask for it.
+ */
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, entry_name));
+ g_assert (widget);
+ value = gtk_entry_get_text (GTK_ENTRY (widget));
+ if (value && strlen (value))
+ default_idx = 0;
+
+ store = GTK_LIST_STORE(gtk_builder_get_object (priv->builder, "pass_type_model"));
+ g_assert (store);
+
+ if (s_vpn)
+ nm_setting_get_secret_flags (NM_SETTING (s_vpn),
+ secret_key,
+ &pw_flags,
+ NULL);
+ if ((active < 0)
+ && !(pw_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED)
+ && !(pw_flags & NM_SETTING_SECRET_FLAG_NOT_REQUIRED)) {
+ active = PW_TYPE_SAVE;
+ }
+
+ if ((active < 0) && (pw_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED))
+ active = PW_TYPE_ASK;
+
+ if ((active < 0) && (pw_flags & NM_SETTING_SECRET_FLAG_NOT_REQUIRED))
+ active = PW_TYPE_UNUSED;
+
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, combo_name));
+ g_assert (widget);
+ gtk_combo_box_set_active (GTK_COMBO_BOX (widget),
+ active < 0 ? default_idx : active);
+
+ pw_type_combo_changed_cb (widget, self);
+ g_signal_connect (G_OBJECT (widget),
+ "changed",
+ G_CALLBACK (pw_type_combo_changed_cb), self);
+}
+
+static gboolean
+init_plugin_ui (IodinePluginUiWidget *self,
+ NMConnection *connection,
+ GError **error)
+{
+ IodinePluginUiWidgetPrivate *priv = \
+ IODINE_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
+ NMSettingVPN *s_vpn;
+ GtkWidget *widget;
+ const char *value;
+
+ s_vpn = (NMSettingVPN *) nm_connection_get_setting (connection,
+ NM_TYPE_SETTING_VPN);
+
+ priv->group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
+ "topdomain_entry"));
+ if (!widget)
+ return FALSE;
+ gtk_size_group_add_widget (priv->group, widget);
+ if (s_vpn) {
+ value = nm_setting_vpn_get_data_item (s_vpn, NM_IODINE_KEY_TOPDOMAIN);
+ if (value)
+ gtk_entry_set_text (GTK_ENTRY (widget), value);
+ }
+ g_signal_connect (G_OBJECT (widget),
+ "changed",
+ G_CALLBACK (stuff_changed_cb), self);
+
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
+ "nameserver_entry"));
+ if (!widget)
+ return FALSE;
+ gtk_size_group_add_widget (priv->group, widget);
+ if (s_vpn) {
+ value = nm_setting_vpn_get_data_item (s_vpn, NM_IODINE_KEY_NAMESERVER);
+ if (value)
+ gtk_entry_set_text (GTK_ENTRY (widget), value);
+ }
+ g_signal_connect (G_OBJECT (widget),
+ "changed",
+ G_CALLBACK (stuff_changed_cb), self);
+
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
+ "fragsize_entry"));
+ if (!widget)
+ return FALSE;
+ if (s_vpn) {
+ value = nm_setting_vpn_get_data_item (s_vpn, NM_IODINE_KEY_FRAGSIZE);
+ if (value)
+ gtk_entry_set_text (GTK_ENTRY (widget), value);
+ }
+ g_signal_connect (G_OBJECT (widget),
+ "changed",
+ G_CALLBACK (stuff_changed_cb), self);
+
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
+ "show_passwords_checkbutton"));
+ g_signal_connect (G_OBJECT (widget), "toggled",
+ (GCallback) show_toggled_cb,
+ self);
+
+ setup_password_widget (self,
+ "password_entry",
+ s_vpn,
+ NM_IODINE_KEY_PASSWORD);
+
+ init_one_pw_combo (self,
+ s_vpn,
+ "pass_type_combo",
+ NM_IODINE_KEY_PASSWORD,
+ "password_entry");
+ return TRUE;
+}
+
+static GObject *
+get_widget (NMVpnPluginUiWidgetInterface *iface)
+{
+ IodinePluginUiWidget *self = IODINE_PLUGIN_UI_WIDGET (iface);
+ IodinePluginUiWidgetPrivate *priv = IODINE_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
+
+ return G_OBJECT (priv->widget);
+}
+
+static void
+save_password_and_flags (NMSettingVPN *s_vpn,
+ GtkBuilder *builder,
+ const char *entry_name,
+ const char *combo_name,
+ const char *secret_key)
+{
+ NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
+ const char *password;
+ GtkWidget *entry;
+ GtkWidget *combo;
+
+ /* Grab original password flags */
+ entry = GTK_WIDGET (gtk_builder_get_object (builder, entry_name));
+ flags = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (entry), "flags"));
+
+ /* And set new ones based on the type combo */
+ combo = GTK_WIDGET (gtk_builder_get_object (builder, combo_name));
+
+ switch (gtk_combo_box_get_active (GTK_COMBO_BOX (combo))) {
+ case PW_TYPE_SAVE:
+ password = gtk_entry_get_text (GTK_ENTRY (entry));
+ if (password && strlen (password))
+ nm_setting_vpn_add_secret (s_vpn, secret_key, password);
+ break;
+ case PW_TYPE_UNUSED:
+ flags |= NM_SETTING_SECRET_FLAG_NOT_REQUIRED;
+ break;
+ case PW_TYPE_ASK:
+ default:
+ flags |= NM_SETTING_SECRET_FLAG_NOT_SAVED;
+ break;
+ }
+
+ /* Set new secret flags */
+ nm_setting_set_secret_flags (NM_SETTING (s_vpn), secret_key, flags, NULL);
+}
+
+static gboolean
+update_connection (NMVpnPluginUiWidgetInterface *iface,
+ NMConnection *connection,
+ GError **error)
+{
+ IodinePluginUiWidget *self = IODINE_PLUGIN_UI_WIDGET (iface);
+ IodinePluginUiWidgetPrivate *priv = \
+ IODINE_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
+ NMSettingVPN *s_vpn;
+ GtkWidget *widget;
+ char *str;
+
+ if (!check_validity (self, error))
+ return FALSE;
+
+ s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ());
+ g_object_set (s_vpn, NM_SETTING_VPN_SERVICE_TYPE,
+ NM_DBUS_SERVICE_IODINE,
+ NULL);
+
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
+ "topdomain_entry"));
+ g_assert(widget);
+ str = (char *) gtk_entry_get_text (GTK_ENTRY (widget));
+ if (str && strlen (str))
+ nm_setting_vpn_add_data_item (s_vpn, NM_IODINE_KEY_TOPDOMAIN, str);
+
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
+ "nameserver_entry"));
+ g_assert(widget);
+ str = (char *) gtk_entry_get_text (GTK_ENTRY (widget));
+ if (str && strlen (str))
+ nm_setting_vpn_add_data_item (s_vpn, NM_IODINE_KEY_NAMESERVER, str);
+
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
+ "fragsize_entry"));
+ g_assert(widget);
+ str = (char *) gtk_entry_get_text (GTK_ENTRY (widget));
+ if (str && strlen (str))
+ nm_setting_vpn_add_data_item (s_vpn, NM_IODINE_KEY_FRAGSIZE, str);
+
+ /* User password and flags */
+ save_password_and_flags (s_vpn,
+ priv->builder,
+ "password_entry",
+ "pass_type_combo",
+ NM_IODINE_KEY_PASSWORD);
+
+ nm_connection_add_setting (connection, NM_SETTING (s_vpn));
+ return TRUE;
+}
+
+static NMVpnPluginUiWidgetInterface *
+nm_vpn_plugin_ui_widget_interface_new (NMConnection *connection, GError **error)
+{
+ NMVpnPluginUiWidgetInterface *object;
+ IodinePluginUiWidgetPrivate *priv;
+ char *ui_file;
+
+ if (error)
+ g_return_val_if_fail (*error == NULL, NULL);
+
+ object = NM_VPN_PLUGIN_UI_WIDGET_INTERFACE \
+ (g_object_new (IODINE_TYPE_PLUGIN_UI_WIDGET, NULL));
+
+ if (!object) {
+ g_set_error (error, IODINE_PLUGIN_UI_ERROR, 0,
+ "could not create iodine object");
+ return NULL;
+ }
+
+ priv = IODINE_PLUGIN_UI_WIDGET_GET_PRIVATE (object);
+ ui_file = g_strdup_printf ("%s/%s", UIDIR, "nm-iodine-dialog.ui");
+ priv->builder = gtk_builder_new ();
+
+ gtk_builder_set_translation_domain (priv->builder, GETTEXT_PACKAGE);
+ if (!gtk_builder_add_from_file (priv->builder, ui_file, error)) {
+ g_warning ("Couldn't load builder file: %s",
+ error && *error ? (*error)->message : "(unknown)");
+ g_clear_error (error);
+ g_set_error (error, IODINE_PLUGIN_UI_ERROR, 0,
+ "could not load required resources at %s", ui_file);
+ g_free (ui_file);
+ g_object_unref (object);
+ return NULL;
+ }
+ g_free (ui_file);
+
+ priv->widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
+ "iodine-vbox"));
+ if (!priv->widget) {
+ g_set_error (error, IODINE_PLUGIN_UI_ERROR, 0,
+ "could not load UI widget");
+ g_object_unref (object);
+ return NULL;
+ }
+ g_object_ref_sink (priv->widget);
+
+ if (!init_plugin_ui (IODINE_PLUGIN_UI_WIDGET (object), connection, error)) {
+ g_object_unref (object);
+ return NULL;
+ }
+
+ return object;
+}
+
+static void
+dispose (GObject *object)
+{
+ IodinePluginUiWidget *plugin = IODINE_PLUGIN_UI_WIDGET (object);
+ IodinePluginUiWidgetPrivate *priv = \
+ IODINE_PLUGIN_UI_WIDGET_GET_PRIVATE (plugin);
+
+ if (priv->group)
+ g_object_unref (priv->group);
+
+ if (priv->widget)
+ g_object_unref (priv->widget);
+
+ if (priv->builder)
+ g_object_unref (priv->builder);
+
+ G_OBJECT_CLASS (iodine_plugin_ui_widget_parent_class)->dispose (object);
+}
+
+static void
+iodine_plugin_ui_widget_class_init (IodinePluginUiWidgetClass *req_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (req_class);
+
+ g_type_class_add_private (req_class, sizeof (IodinePluginUiWidgetPrivate));
+
+ object_class->dispose = dispose;
+}
+
+static void
+iodine_plugin_ui_widget_init (IodinePluginUiWidget *plugin)
+{
+}
+
+static void
+iodine_plugin_ui_widget_interface_init (NMVpnPluginUiWidgetInterface *iface_class)
+{
+ /* interface implementation */
+ iface_class->get_widget = get_widget;
+ iface_class->update_connection = update_connection;
+}
+
+static guint32
+get_capabilities (NMVpnPluginUiInterface *iface)
+{
+ return (NM_VPN_PLUGIN_UI_CAPABILITY_IMPORT |
+ NM_VPN_PLUGIN_UI_CAPABILITY_EXPORT);
+}
+
+static NMVpnPluginUiWidgetInterface *
+ui_factory (NMVpnPluginUiInterface *iface,
+ NMConnection *connection,
+ GError **error)
+{
+ return nm_vpn_plugin_ui_widget_interface_new (connection, error);
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+ GValue *value, GParamSpec *pspec)
+{
+ switch (prop_id) {
+ case NM_VPN_PLUGIN_UI_INTERFACE_PROP_NAME:
+ g_value_set_string (value, IODINE_PLUGIN_NAME);
+ break;
+ case NM_VPN_PLUGIN_UI_INTERFACE_PROP_DESC:
+ g_value_set_string (value, IODINE_PLUGIN_DESC);
+ break;
+ case NM_VPN_PLUGIN_UI_INTERFACE_PROP_SERVICE:
+ g_value_set_string (value, IODINE_PLUGIN_SERVICE);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+iodine_plugin_ui_class_init (IodinePluginUiClass *req_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (req_class);
+
+ object_class->get_property = get_property;
+
+ g_object_class_override_property (object_class,
+ NM_VPN_PLUGIN_UI_INTERFACE_PROP_NAME,
+ NM_VPN_PLUGIN_UI_INTERFACE_NAME);
+
+ g_object_class_override_property (object_class,
+ NM_VPN_PLUGIN_UI_INTERFACE_PROP_DESC,
+ NM_VPN_PLUGIN_UI_INTERFACE_DESC);
+
+ g_object_class_override_property (object_class,
+ NM_VPN_PLUGIN_UI_INTERFACE_PROP_SERVICE,
+ NM_VPN_PLUGIN_UI_INTERFACE_SERVICE);
+}
+
+static void
+iodine_plugin_ui_init (IodinePluginUi *plugin)
+{
+}
+
+static void
+iodine_plugin_ui_interface_init (NMVpnPluginUiInterface *iface_class)
+{
+ /* interface implementation */
+ iface_class->ui_factory = ui_factory;
+ iface_class->get_capabilities = get_capabilities;
+ iface_class->import_from_file = import;
+ iface_class->export_to_file = export;
+}
+
+G_MODULE_EXPORT NMVpnPluginUiInterface *
+nm_vpn_plugin_ui_factory (GError **error)
+{
+ if (error)
+ g_return_val_if_fail (*error == NULL, NULL);
+
+ return NM_VPN_PLUGIN_UI_INTERFACE (g_object_new (IODINE_TYPE_PLUGIN_UI,
+ NULL));
+}
diff --git a/properties/nm-iodine.h b/properties/nm-iodine.h
new file mode 100644
index 0000000..1769fff
--- /dev/null
+++ b/properties/nm-iodine.h
@@ -0,0 +1,83 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * GNOME UI dialogs for configuring iodine VPN connections
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright © 2012 Guido Günther <agx@sigxcpu.org>
+ */
+
+#ifndef _NM_IODINE_H_
+#define _NM_IODINE_H_
+
+#include <glib-object.h>
+
+typedef enum
+{
+ IODINE_PLUGIN_UI_ERROR_UNKNOWN = 0,
+ IODINE_PLUGIN_UI_ERROR_INVALID_PROPERTY,
+ IODINE_PLUGIN_UI_ERROR_MISSING_PROPERTY
+} IodinePluginUiError;
+
+
+GQuark iodine_plugin_ui_error_quark (void);
+#define IODINE_PLUGIN_UI_ERROR iodine_plugin_ui_error_quark ()
+
+#define IODINE_TYPE_PLUGIN_UI_ERROR (iodine_plugin_ui_error_get_type ())
+GType iodine_plugin_ui_error_get_type (void);
+
+#define IODINE_TYPE_PLUGIN_UI (iodine_plugin_ui_get_type ())
+#define IODINE_PLUGIN_UI(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IODINE_TYPE_PLUGIN_UI, IodinePluginUi))
+#define IODINE_PLUGIN_UI_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), IODINE_TYPE_PLUGIN_UI, IodinePluginUiClass))
+#define IODINE_IS_PLUGIN_UI(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IODINE_TYPE_PLUGIN_UI))
+#define IODINE_IS_PLUGIN_UI_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), IODINE_TYPE_PLUGIN_UI))
+#define IODINE_PLUGIN_UI_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), IODINE_TYPE_PLUGIN_UI, IodinePluginUiClass))
+
+typedef struct _IodinePluginUi IodinePluginUi;
+typedef struct _IodinePluginUiClass IodinePluginUiClass;
+
+struct _IodinePluginUi {
+ GObject parent;
+};
+
+struct _IodinePluginUiClass {
+ GObjectClass parent;
+};
+
+GType iodine_plugin_ui_get_type (void);
+
+
+#define IODINE_TYPE_PLUGIN_UI_WIDGET (iodine_plugin_ui_widget_get_type ())
+#define IODINE_PLUGIN_UI_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IODINE_TYPE_PLUGIN_UI_WIDGET, IodinePluginUiWidget))
+#define IODINE_PLUGIN_UI_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), IODINE_TYPE_PLUGIN_UI_WIDGET, IodinePluginUiWidgetClass))
+#define IODINE_IS_PLUGIN_UI_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IODINE_TYPE_PLUGIN_UI_WIDGET))
+#define IODINE_IS_PLUGIN_UI_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), IODINE_TYPE_PLUGIN_UI_WIDGET))
+#define IODINE_PLUGIN_UI_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), IODINE_TYPE_PLUGIN_UI_WIDGET, IodinePluginUiWidgetClass))
+
+typedef struct _IodinePluginUiWidget IodinePluginUiWidget;
+typedef struct _IodinePluginUiWidgetClass IodinePluginUiWidgetClass;
+
+struct _IodinePluginUiWidget {
+ GObject parent;
+};
+
+struct _IodinePluginUiWidgetClass {
+ GObjectClass parent;
+};
+
+GType iodine_plugin_ui_widget_get_type (void);
+
+#endif /* _NM_IODINE_H_ */
+