Split the config part into a new file.
authorRoy Marples <roy@marples.name>
Thu, 5 Mar 2009 01:09:11 +0000 (01:09 +0000)
committerRoy Marples <roy@marples.name>
Thu, 5 Mar 2009 01:09:11 +0000 (01:09 +0000)
Make the prefs easier - anything more complicated and the user will have
to edit the config file directly for the time being.
NOTE: It doesn't work quite yet ....

Makefile
dhcpcd-config.c [new file with mode: 0644]
dhcpcd-config.h [new file with mode: 0644]
dhcpcd-gtk.h
prefs.c

index 2f2f9a0560822ef6fac21a03870fbfb8b784bf89..51768e3b9a1f0535452b8bd9b8cb681eb94776de 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@
 # Copyright 2008 Roy Marples <roy@marples.name>
 
 PROG=          dhcpcd-gtk
-SRCS=          main.c menu.c prefs.c wpa.c
+SRCS=          main.c menu.c dhcpcd-config.c prefs.c wpa.c
 
 SYSCONFDIR?=   ${PREFIX}/etc/xdg/autostart
 FILESDIR?=     ${SYSCONFDIR}
diff --git a/dhcpcd-config.c b/dhcpcd-config.c
new file mode 100644 (file)
index 0000000..77122d3
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * dhcpcd-gtk
+ * Copyright 2009 Roy Marples <roy@marples.name>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "dhcpcd-config.h"
+#include "dhcpcd-gtk.h"
+
+void
+free_config(GPtrArray **config)
+{
+       unsigned int i;
+
+       if (config == NULL || *config == NULL)
+               return;
+       for (i = 0; i < (*config)->len; i++)
+               g_value_array_free(g_ptr_array_index(*config, i));
+       g_ptr_array_free(*config, TRUE);
+       *config = NULL;
+}      
+
+GPtrArray *
+read_config(const char *block, const char *name)
+{
+       GType otype;
+       GError *error;
+       GPtrArray *config;
+
+       error = NULL;
+       otype = dbus_g_type_get_struct("GValueArray",
+           G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
+       otype = dbus_g_type_get_collection("GPtrArray", otype);
+       if (!dbus_g_proxy_call(dbus, "GetConfig", &error,
+               G_TYPE_STRING, block, G_TYPE_STRING, name, G_TYPE_INVALID,
+               otype, &config, G_TYPE_INVALID))
+       {
+               g_critical("GetConfig: %s", error->message);
+               g_clear_error(&error);
+               return NULL;
+       }
+       return config;
+}
+
+int
+get_config(GPtrArray *config, int idx, const char *opt, const char **value)
+{
+       GValueArray *c;
+       GValue *val;
+       const char *str;
+
+       if (config == NULL)
+               return -1;
+       for (; (uint)idx < config->len; idx++) {
+               c = g_ptr_array_index(config, idx);
+               val = g_value_array_get_nth(c, 0);
+               str = g_value_get_string(val);
+               if (strcmp(str, opt) != 0)
+                       continue;
+               if (value != NULL) {
+                       val = g_value_array_get_nth(c, 1);
+                       str = g_value_get_string(val);
+                       if (*str == '\0')
+                               *value = NULL;
+                       else
+                               *value = str;
+               }
+               return idx;
+       }
+       if (value != NULL)
+               *value = NULL;
+       return -1;
+}
+
+int
+get_static_config(GPtrArray *config, const char *var, const char **value)
+{
+       int idx;
+       const char *val;
+
+       idx = -1;
+       while ((idx = get_config(config, idx + 1, "static", &val)) != -1) {
+               if (g_str_has_prefix(val, var)) {
+                       if (value)
+                               *value = val + strlen(var);
+                       return idx;
+               }
+       }
+       if (value)
+               *value = NULL;
+       return -1;
+}
+
+GPtrArray *
+save_config(const char *block, const char *name, GPtrArray *config)
+{
+       GError *error;
+       GType otype;
+       
+       error = NULL;
+       otype = dbus_g_type_get_struct("GValueArray",
+           G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
+       otype = dbus_g_type_get_collection("GPtrArray", otype);
+       if (!dbus_g_proxy_call(dbus, "SetConfig", &error,
+               G_TYPE_STRING, block,
+               G_TYPE_STRING, name,
+               otype, config,
+               G_TYPE_INVALID,
+               G_TYPE_INVALID))
+       {
+               g_critical("SetConfig: %s", error->message);
+               g_clear_error(&error);
+               return NULL;
+       }
+       return config;
+}
+
+GPtrArray *
+load_config(const char *block, const char *name, GPtrArray *array)
+{
+
+       free_config(&array);
+       return read_config(block, name);
+}
+
+void
+set_option(GPtrArray *array, bool sopt, const char *var, const char *val)
+{
+       int i;
+       GValueArray *va;
+       GValue nv, *v;
+       char *n;
+
+       if (sopt)
+               i = get_static_config(array, var, NULL);
+       else
+               i = get_config(array, 0, var, NULL);
+       if (val == NULL) {
+               if (i != -1) {
+                       va = g_ptr_array_remove_index(array, i);
+                       g_value_array_free(va);
+               }
+       } else {
+               if (sopt)
+                       n = g_strconcat(var, val, NULL);
+               else
+                       n = NULL;
+               if (i == -1) {
+                       va = g_value_array_new(2);
+                       memset(&nv, 0, sizeof(v));
+                       g_value_init(&nv, G_TYPE_STRING);
+                       g_value_set_static_string(&nv, sopt ? "static" : var);
+                       va = g_value_array_append(va, &nv);
+                       g_value_set_static_string(&nv, sopt ? n : val);
+                       va = g_value_array_append(va, &nv);
+                       g_ptr_array_add(array, va);
+               } else if (val != NULL) {
+                       va = g_ptr_array_index(array, i);
+                       v = g_value_array_get_nth(va, 1);
+                       g_value_unset(v);
+                       g_value_init(v, G_TYPE_STRING);
+                       g_value_set_static_string(v, sopt ? n : val);
+               }
+               g_free(n);
+       }
+}
diff --git a/dhcpcd-config.h b/dhcpcd-config.h
new file mode 100644 (file)
index 0000000..194137d
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * dhcpcd-gtk
+ * Copyright 2009 Roy Marples <roy@marples.name>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef DHCPCD_CONFIG_H
+#define DHCPCD_CONFIG_H
+
+#include <stdbool.h>
+
+#include <glib.h>
+
+void free_config(GPtrArray **);
+GPtrArray *read_config(const char *, const char *);
+int get_config(GPtrArray *, int, const char *, const char **);
+int get_static_config(GPtrArray *, const char *, const char **);
+GPtrArray *save_config(const char *, const char *, GPtrArray *);
+GPtrArray *load_config(const char *, const char *, GPtrArray *);
+void set_option(GPtrArray *, bool, const char *, const char *);
+
+#endif
index fe300ea9a2c8a6164d8ef8db5fb86b20801850c1..33a511bcc31fbb8658df3a469314289f95303860 100644 (file)
@@ -29,6 +29,8 @@
 
 #include <arpa/inet.h>
 
+#include <stdbool.h>
+
 #include <dbus/dbus-glib.h>
 #include <glib.h>
 #include <glib/gi18n.h>
@@ -69,7 +71,7 @@ struct if_msg {
        char *reason;
        struct in_addr ip;
        unsigned char cidr;
-       gboolean wireless;
+       bool wireless;
        char *ssid;
        GSList *scan_results;
 };
diff --git a/prefs.c b/prefs.c
index b0c62a081d6ee49b812c82a3bf47ed80eff83d28..2e872d2c4ea19d5f1f27394cd31fe6857b01b8d7 100644 (file)
--- a/prefs.c
+++ b/prefs.c
  * SUCH DAMAGE.
  */
 
-#include <dbus/dbus.h>
+#include <errno.h>
 
+#include "dhcpcd-config.h"
 #include "dhcpcd-gtk.h"
 #include "prefs.h"
 
-static GPtrArray *config;
 static GtkWidget *dialog, *blocks, *names, *controls;
-static GtkWidget *hostname, *fqdn, *clientid, *duid, *arp, *ipv4ll;
-static gboolean ignore_change;
+static GtkWidget *autoconf, *address, *router, *dns_servers, *dns_search;
+static GtkWidget *ntp_servers;
+static GPtrArray *config;
+static char *block, *name;
+static bool ignore_change;
 
 static void
-free_config(GPtrArray **array)
-{
-       GPtrArray *a;
-       guint i;
-       GValueArray *c;
-
-       a = *array;
-       if (a == NULL)
-               return;
-       for (i = 0; i < a->len; i++) {
-               c = g_ptr_array_index(a, i);
-               g_value_array_free(c);
-       }
-       g_ptr_array_free(a, TRUE);
-       *array = NULL;
-}      
-
-static GPtrArray *
-read_config(const char *block, const char *name)
+show_config(GPtrArray *array)
 {
-       GType otype;
-       GError *error;
-       GPtrArray *array;
-
-       error = NULL;
-       otype = dbus_g_type_get_struct("GValueArray",
-           G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
-       otype = dbus_g_type_get_collection("GPtrArray", otype);
-       if (!dbus_g_proxy_call(dbus, "GetConfig", &error,
-               G_TYPE_STRING, block, G_TYPE_STRING, name, G_TYPE_INVALID,
-               otype, &array, G_TYPE_INVALID))
-       {
-               g_critical("GetConfig: %s", error->message);
-               g_clear_error(&error);
-               return NULL;
-       }
-       return array;
-}
+       const char *val;
+       bool autocnf;
 
-static gboolean
-get_config(GPtrArray *array, const char *option, const char **value)
-{
-       guint i;
-       GValueArray *c;
-       GValue *val;
-       const char *str;
-
-       if (array == NULL)
-               return FALSE;
-       for (i = 0; i < array->len; i++) {
-               c = g_ptr_array_index(array, i);
-               val = g_value_array_get_nth(c, 0);
-               str = g_value_get_string(val);
-               if (strcmp(str, option) != 0)
-                       continue;
-               if (value != NULL) {
-                       val = g_value_array_get_nth(c, 1);
-                       str = g_value_get_string(val);
-                       if (*str == '\0')
-                               *value = NULL;
-                       else
-                               *value = str;
-               }
-               return TRUE;
+       ignore_change = TRUE;
+       if (get_static_config(array, "ip_address=", &val) != -1)
+               autocnf = false;
+       else {
+               get_config(array, 0, "inform", &val);
+               autocnf = true;
        }
-       if (value != NULL)
-               *value = NULL;
-       return FALSE;
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(autoconf), autocnf);
+       gtk_entry_set_text(GTK_ENTRY(address), val ? val : "");
+       get_static_config(array, "routers=", &val);
+       gtk_entry_set_text(GTK_ENTRY(router), val ? val : "");
+       get_static_config(array, "domain_name_servers=", &val);
+       gtk_entry_set_text(GTK_ENTRY(dns_servers), val ? val : "");
+       get_static_config(array, "domain_name_search=", &val);
+       gtk_entry_set_text(GTK_ENTRY(dns_search), val ? val : "");
+       get_static_config(array, "ntp_servers=", &val);
+       gtk_entry_set_text(GTK_ENTRY(ntp_servers), val ? val : "");
+       ignore_change = FALSE;
 }
 
 static char *
@@ -124,6 +82,40 @@ combo_active_text(GtkWidget *widget)
 }
 
 static void
+make_config(GPtrArray *array)
+{
+       const char *val;
+       bool a;
+
+       a = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(autoconf));
+       val = gtk_entry_get_text(GTK_ENTRY(address));
+       if (*val == '\0')
+               val = NULL;
+       set_option(array, false, "inform", a ? val : NULL);
+       set_option(array, true, "ip_address=", a ? NULL : val);
+       
+       val = gtk_entry_get_text(GTK_ENTRY(router));
+       if (a && *val == '\0')
+               val = NULL;
+       set_option(array, true, "routers=", val);
+       
+       val = gtk_entry_get_text(GTK_ENTRY(dns_servers));
+       if (a && *val == '\0')
+               val = NULL;
+       set_option(array, true, "domain_name_servers=", val);
+       
+       val = gtk_entry_get_text(GTK_ENTRY(dns_search));
+       if (a && *val == '\0')
+               val = NULL;
+       set_option(array, true, "domain_name_search=", val);
+       
+       val = gtk_entry_get_text(GTK_ENTRY(ntp_servers));
+       if (a && *val == '\0')
+               val = NULL;
+       set_option(array, true, "ntp_servers=", val);
+}
+
+static void
 set_name_active_icon(const char *iname)
 {
        GtkListStore *store;
@@ -147,136 +139,6 @@ set_name_active_icon(const char *iname)
        }
 }
 
-static gboolean
-set_option(const char *option, const char *value)
-{
-       GError *error;
-       char *name, *block;
-       gboolean retval;
-
-       block = combo_active_text(blocks);
-       name = combo_active_text(names);
-       error = NULL;
-       if (!dbus_g_proxy_call(dbus, "SetConfigValue", &error,
-               G_TYPE_STRING, name ? block : "",
-               G_TYPE_STRING, name ? name : "",
-               G_TYPE_STRING, option, G_TYPE_STRING, value,
-               G_TYPE_INVALID, G_TYPE_INVALID))
-       {
-               g_critical("SetConfigValue: %s", error->message);
-               g_clear_error(&error);
-               retval = FALSE;
-       } else
-               retval = TRUE;
-       g_free(block);
-       g_free(name);
-       set_name_active_icon("document-save");
-       return retval;
-}
-
-static gboolean
-unset_option(const char *option)
-{
-       GError *error;
-       char *name, *block;
-       gboolean retval;
-
-       block = combo_active_text(blocks);
-       name = combo_active_text(names);
-       error = NULL;
-       if (!dbus_g_proxy_call(dbus, "RemoveConfigOption", &error,
-               G_TYPE_STRING, name ? block : "" ,
-               G_TYPE_STRING, name ? name : "",
-               G_TYPE_STRING, option,
-               G_TYPE_INVALID, G_TYPE_INVALID))
-       {
-               g_critical("RemoveConfigOption: %s", error->message);
-               g_clear_error(&error);
-               retval = FALSE;
-       } else
-               retval = TRUE;
-       g_free(block);
-       g_free(name);
-       set_name_active_icon("document-save");
-       return retval;
-}
-
-static gboolean
-toggle_generic(gboolean has, const char *val)
-{
-       return (has && (val == NULL || g_strcmp0(val, "\"\"") == 0));
-}
-
-static gboolean
-toggle_generic_neg(gboolean has, _unused const char *val)
-{
-       return !has;
-}
-
-static gboolean
-toggle_fqdn(gboolean has, const char *val)
-{
-       return (has &&
-           (val == NULL ||
-               g_strcmp0(val, "both") == 0 ||
-               g_strcmp0(val, "ptr") == 0));
-}
-
-static void
-set_check(GtkToggleButton *button,
-    GPtrArray *global, GPtrArray *conf, const char *name,
-    gboolean (*test)(gboolean, const char *))
-{
-       const char *val;
-       gboolean has, incons;
-       
-       if (get_config(conf, name, &val)) {
-               has = TRUE;
-               incons = FALSE;
-       } else if (global == NULL) {
-               incons = FALSE;
-               has = FALSE;
-       } else {
-               has = get_config(global, name, &val);
-               incons = TRUE;
-       }
-       gtk_toggle_button_set_active(button, test(has, val));
-       gtk_toggle_button_set_inconsistent(button, incons);
-}
-
-static void
-show_config(const char *block, const char *name)
-{
-       GPtrArray *global;
-
-       ignore_change = TRUE;
-       if (block || name)
-               global = read_config(NULL, NULL);
-       else
-               global = NULL;
-       
-       free_config(&config);
-       config = read_config(block, name);
-       set_check(GTK_TOGGLE_BUTTON(hostname), global, config,
-           "hostname", toggle_generic);
-       set_check(GTK_TOGGLE_BUTTON(fqdn), global, config,
-           "fqdn", toggle_fqdn);
-       set_check(GTK_TOGGLE_BUTTON(clientid), global, config,
-           "clientid", toggle_generic);
-       set_check(GTK_TOGGLE_BUTTON(duid), global, config,
-           "duid", toggle_generic);
-       gtk_widget_set_sensitive(duid,
-           gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(clientid)));
-       set_check(GTK_TOGGLE_BUTTON(arp), global, config,
-           "noarp", toggle_generic_neg);
-       set_check(GTK_TOGGLE_BUTTON(ipv4ll), global, config,
-           "noipv4ll", toggle_generic_neg);
-       gtk_widget_set_sensitive(ipv4ll,
-           gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(arp)));
-       free_config(&global);
-       ignore_change = FALSE;
-}
-
 static GSList *
 list_interfaces(void)
 {
@@ -317,34 +179,33 @@ list_ssids(void)
 }
 
 static void
-blocks_on_change(GtkWidget *widget, _unused gpointer data)
+blocks_on_change(GtkWidget *widget)
 {
        GtkListStore *store;
        GtkTreeIter iter;
        GError *error;
-       char **list, **lp, *block;
+       char **list, **lp;
        const char *iname, *nn;
        GSList *l, *new_names;
        GtkIconTheme *it;
        GdkPixbuf *pb;
-       gint n;
+       int n;
 
+       if (name) {
+               make_config(config);
+               save_config(block, name, config);
+               g_free(block);
+               g_free(name);
+               name = NULL;
+       }
        block = combo_active_text(widget);
        store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(names)));
        gtk_list_store_clear(store);
-       if (strcmp(block, "global") == 0) {
-               g_free(block);
-               gtk_widget_set_sensitive(names, FALSE);
-               gtk_widget_set_sensitive(controls, TRUE);
-               show_config(NULL, NULL);
-               return;
-       }
        error = NULL;
        if (!dbus_g_proxy_call(dbus, "GetConfigBlocks", &error,
                G_TYPE_STRING, block, G_TYPE_INVALID,
                G_TYPE_STRV, &list, G_TYPE_INVALID))
        {
-               g_free(block);
                g_warning("GetConfigBlocks: %s", error->message);
                g_clear_error(&error);
                return;
@@ -391,64 +252,100 @@ blocks_on_change(GtkWidget *widget, _unused gpointer data)
        gtk_widget_set_sensitive(controls, FALSE);
        g_slist_free(new_names);
        g_strfreev(list);
-       g_free(block);
 }
 
 static void
-names_on_change(GtkWidget *widget, _unused gpointer data)
+names_on_change(void)
 {
-       char *block, *name;
-
-       block = combo_active_text(blocks);
-       name = combo_active_text(widget);
+       
+       if (name) {
+               make_config(config);
+               save_config(block, name, config);
+               g_free(name);
+       }
        gtk_widget_set_sensitive(controls, TRUE);
-       show_config(block, name);
-       g_free(block);
-       g_free(name);
+       name = combo_active_text(names);
+       config = load_config(block, name, config);
+       show_config(config);
 }
 
-static void
-_on_toggle_set(GtkWidget *widget, gpointer data, gboolean set)
+static bool
+valid_address(const char *val, bool allow_cidr)
 {
-       gboolean active, result;
-
-       if (ignore_change)
-               return;
-       gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(widget), FALSE);
-       active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
-       if ((active && set) || (!active && !set))
-               result = set_option((const char *)data, "");
-       else
-               result = unset_option((const char *)data);
-       if (!result)
-               gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
-                   !(active && set));
+       char *addr, *p, *e;
+       struct in_addr in;
+       gint64 cidr;
+       bool retval;
+
+       addr = g_strdup(val);
+       if (allow_cidr) {
+               p = strchr(addr, '/');
+               if (p != NULL) {
+                       *p++ = '\0';
+                       errno = 0;
+                       e = NULL;
+                       cidr = g_ascii_strtoll(p, &e, 10);
+                       if (cidr < 0 || cidr > 32 ||
+                           errno != 0 || *e != '\0')
+                       {
+                               retval = false;
+                               goto out;
+                       }
+               }
+       }
+       retval = inet_aton(addr, &in) == 0 ? false : true;
+       
+out:
+       g_free(addr);
+       return retval;
 }
 
-static void
-on_toggle_set(GtkWidget *widget, gpointer data)
+       
+static bool
+address_lost_focus(GtkEntry *entry)
 {
-       _on_toggle_set(widget, data, TRUE);
+       const char *val;
+
+       val = gtk_entry_get_text(entry);
+       if (*val != '\0' && !valid_address(val, true))
+               gtk_entry_set_text(entry, "");
+       return false;
 }
 
-static void
-on_toggle_unset(GtkWidget *widget, gpointer data)
+static bool
+entry_lost_focus(GtkEntry *entry)
 {
-       _on_toggle_set(widget, data, FALSE);
+       const char *val;
+       char **a, **p;
+
+       val = gtk_entry_get_text(entry);
+       a = g_strsplit(val, " ", 0);
+       for (p = a; *p; p++) {
+               if (**p != '\0' && !valid_address(*p, false)) {
+                       gtk_entry_set_text(entry, "");
+                       break;
+               }
+       }
+       g_strfreev(a);
+       return false;
 }
 
 static void
-on_toggle_set_sens(GtkWidget *widget, gpointer data)
+on_clear(void)
 {
-       gboolean active;
 
-       active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
-       gtk_widget_set_sensitive(GTK_WIDGET((GtkWidget *)data), active);
+       free_config(&config);
+       config = g_ptr_array_new();
+       if (save_config(block, name, config)) {
+               set_name_active_icon("document-new");
+               show_config(config);
+       }
 }
 
 static void
 on_destroy(void)
 {
+       
        free_config(&config);
        dialog = NULL;
 }
@@ -456,40 +353,21 @@ on_destroy(void)
 void
 dhcpcd_prefs_close(void)
 {
-       if (dialog) {
+       
+       if (dialog != NULL) {
+               if (name != NULL) {
+                       make_config(config);
+                       save_config(block, name, config);
+               }
                gtk_widget_destroy(dialog);
                dialog = NULL;
        }
 }
 
-static void
-on_redo(void)
-{
-       char *block, *name;
-       GError *error;
-
-       block = combo_active_text(blocks);
-       name = combo_active_text(names);
-       error = NULL;
-       if (!dbus_g_proxy_call(dbus, "SetDefaultConfig", &error,
-               G_TYPE_STRING, name ? block : "",
-               G_TYPE_STRING, name ? name : "",
-               G_TYPE_INVALID,
-               G_TYPE_INVALID))
-       {
-               g_critical("SetDefaultConfig: %s", error->message);
-               g_clear_error(&error);
-       }
-       set_name_active_icon("document-new");
-       show_config(name ? block : NULL, name);
-       g_free(block);
-       g_free(name);
-}
-
 void
 dhcpcd_prefs_show(void)
 {
-       GtkWidget *dialog_vbox, *hbox, *vbox, *label;
+       GtkWidget *dialog_vbox, *hbox, *vbox, *table, *w;
        GtkListStore *store;
        GtkTreeIter iter;
        GtkCellRenderer *rend;
@@ -503,7 +381,7 @@ dhcpcd_prefs_show(void)
        }
 
        dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-       gtk_signal_connect(GTK_OBJECT(dialog), "destroy", on_destroy, NULL);
+       g_signal_connect(G_OBJECT(dialog), "destroy", on_destroy, NULL);
 
        gtk_window_set_title(GTK_WINDOW(dialog), _("dhcpcd preferences"));
        gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
@@ -512,21 +390,17 @@ dhcpcd_prefs_show(void)
        gtk_window_set_type_hint(GTK_WINDOW(dialog),
                                 GDK_WINDOW_TYPE_HINT_DIALOG);
 
-       dialog_vbox = gtk_vbox_new(FALSE, 3);
+       dialog_vbox = gtk_vbox_new(FALSE, 10);
+       gtk_container_set_border_width(GTK_CONTAINER(dialog), 10);
        gtk_container_add(GTK_CONTAINER(dialog), dialog_vbox);
 
-       hbox = gtk_hbox_new(FALSE, 10);
+       hbox = gtk_hbox_new(FALSE, 0);
        gtk_box_pack_start(GTK_BOX(dialog_vbox), hbox, FALSE, FALSE, 3);
-       label = gtk_label_new("Configuration block:");
-       gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 3);
+       w = gtk_label_new("Configure:");
+       gtk_box_pack_start(GTK_BOX(hbox), w, FALSE, FALSE, 3);
        store = gtk_list_store_new(2, GDK_TYPE_PIXBUF, G_TYPE_STRING);
        it = gtk_icon_theme_get_default();
        error = NULL;
-       pb = gtk_icon_theme_load_icon(it, "config-users",
-           GTK_ICON_SIZE_MENU, 0, &error);     
-       gtk_list_store_append(store, &iter);
-       gtk_list_store_set(store, &iter, 0, pb, 1, "global", -1);
-       g_object_unref(pb);
        pb = gtk_icon_theme_load_icon(it, "network-wired",
            GTK_ICON_SIZE_MENU, 0, &error);     
        gtk_list_store_append(store, &iter);
@@ -548,8 +422,6 @@ dhcpcd_prefs_show(void)
            rend, "text", 1);
        gtk_combo_box_set_active(GTK_COMBO_BOX(blocks), 0);
        gtk_box_pack_start(GTK_BOX(hbox), blocks, FALSE, FALSE, 3);
-       label = gtk_label_new("Block name:");
-       gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 3);
        store = gtk_list_store_new(2, GDK_TYPE_PIXBUF, G_TYPE_STRING);
        names = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
        rend = gtk_cell_renderer_pixbuf_new();
@@ -561,56 +433,79 @@ dhcpcd_prefs_show(void)
        gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(names), rend, "text", 1);
        gtk_widget_set_sensitive(names, FALSE);
        gtk_box_pack_start(GTK_BOX(hbox), names, FALSE, FALSE, 3);
-       gtk_signal_connect(GTK_OBJECT(blocks), "changed",
+       g_signal_connect(G_OBJECT(blocks), "changed",
            G_CALLBACK(blocks_on_change), NULL);
-       gtk_signal_connect(GTK_OBJECT(names), "changed",
+       g_signal_connect(G_OBJECT(names), "changed",
            G_CALLBACK(names_on_change), NULL);
        
-       label = gtk_hseparator_new();
-       gtk_box_pack_start(GTK_BOX(dialog_vbox), label, TRUE, FALSE, 3);
-       controls = gtk_hbox_new(FALSE, 10);
+       w = gtk_hseparator_new();
+       gtk_box_pack_start(GTK_BOX(dialog_vbox), w, TRUE, FALSE, 3);
+       controls = gtk_vbox_new(FALSE, 10);
        gtk_box_pack_start(GTK_BOX(dialog_vbox), controls, TRUE, TRUE, 0);
        vbox = gtk_vbox_new(FALSE, 3);
        gtk_box_pack_start(GTK_BOX(controls), vbox, FALSE, FALSE, 0);
-       hostname = gtk_check_button_new_with_label(_("Send Hostname"));
-       gtk_signal_connect(GTK_OBJECT(hostname), "toggled",
-           G_CALLBACK(on_toggle_set), UNCONST("hostname"));
-       gtk_box_pack_start(GTK_BOX(vbox), hostname, FALSE, FALSE, 3);
-       fqdn = gtk_check_button_new_with_label(_("Send FQDN"));
-       gtk_signal_connect(GTK_OBJECT(fqdn), "toggled",
-           G_CALLBACK(on_toggle_set), UNCONST("fqdn"));
-       gtk_box_pack_start(GTK_BOX(vbox), fqdn, FALSE, FALSE, 3);
-       clientid = gtk_check_button_new_with_label(_("Send ClientID"));
-       gtk_signal_connect(GTK_OBJECT(clientid), "toggled",
-           G_CALLBACK(on_toggle_set), UNCONST("clientid"));
-       gtk_box_pack_start(GTK_BOX(vbox), clientid, FALSE, FALSE, 3);
-       duid = gtk_check_button_new_with_label(_("Send DUID"));
-       gtk_signal_connect(GTK_OBJECT(duid), "toggled",
-           G_CALLBACK(on_toggle_set), UNCONST("duid"));
-       gtk_signal_connect_after(GTK_OBJECT(clientid), "toggled",
-           G_CALLBACK(on_toggle_set_sens), duid);
-       gtk_box_pack_start(GTK_BOX(vbox), duid, FALSE, FALSE, 3);
-       arp = gtk_check_button_new_with_label(_("Enable ARP checking"));
-       gtk_signal_connect(GTK_OBJECT(arp), "toggled",
-           G_CALLBACK(on_toggle_unset), UNCONST("noarp"));
-       gtk_box_pack_start(GTK_BOX(vbox), arp, FALSE, FALSE, 3);
-       ipv4ll = gtk_check_button_new_with_label(_("Enable Zeroconf"));
-       gtk_box_pack_start(GTK_BOX(vbox), ipv4ll, FALSE, FALSE, 3);
-       gtk_signal_connect(GTK_OBJECT(ipv4ll), "toggled",
-           G_CALLBACK(on_toggle_unset), UNCONST("noipv4ll"));
-       gtk_signal_connect_after(GTK_OBJECT(arp), "toggled",
-           G_CALLBACK(on_toggle_set_sens), ipv4ll);
+       autoconf = gtk_check_button_new_with_label(
+               _("Automatically configure empty options"));
+       gtk_box_pack_start(GTK_BOX(vbox), autoconf, FALSE, FALSE, 3);
+       table = gtk_table_new(6, 2, FALSE);
+       gtk_box_pack_start(GTK_BOX(controls), table, FALSE, FALSE, 0);
+
+#define attach_label(a, b, c, d, e)                                          \
+       do {                                                                  \
+               gtk_misc_set_alignment(GTK_MISC(a), 0.0, 0.5);                \
+               gtk_table_attach(GTK_TABLE(table), a, b, c, d, e,             \
+                   GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 3, 3);      \
+       } while (0)
+#define attach_entry(a, b, c, d, e)                                          \
+       gtk_table_attach(GTK_TABLE(table), a, b, c, d, e,                     \
+           GTK_EXPAND | GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 3, 3); \
+       
+       w = gtk_label_new(_("IP Address:"));
+       address = gtk_entry_new();
+       gtk_entry_set_max_length(GTK_ENTRY(address), 15);
+       g_signal_connect(G_OBJECT(address), "focus-out-event",
+           G_CALLBACK(address_lost_focus), NULL);
+       attach_label(w, 0, 1, 0, 1);
+       attach_entry(address, 1, 2, 0, 1);
+
+       w = gtk_label_new(_("Router:"));
+       router = gtk_entry_new();
+       gtk_entry_set_max_length(GTK_ENTRY(router), 12);
+       g_signal_connect(G_OBJECT(router), "focus-out-event",
+           G_CALLBACK(entry_lost_focus), NULL);
+       attach_label(w, 0, 1, 2, 3);
+       attach_entry(router, 1, 2, 2, 3);
+
+       w = gtk_label_new(_("DNS Servers:"));
+       dns_servers = gtk_entry_new();
+       g_signal_connect(G_OBJECT(dns_servers), "focus-out-event",
+           G_CALLBACK(entry_lost_focus), NULL);
+       attach_label(w, 0, 1, 3, 4);
+       attach_entry(dns_servers, 1, 2, 3, 4);
+
+       w = gtk_label_new(_("DNS Search:"));
+       dns_search = gtk_entry_new();
+       attach_label(w, 0, 1, 4, 5);
+       attach_entry(dns_search, 1, 2, 4, 5);
+
+       w = gtk_label_new(_("NTP Servers:"));
+       ntp_servers = gtk_entry_new();
+       g_signal_connect(G_OBJECT(ntp_servers), "focus-out-event",
+           G_CALLBACK(entry_lost_focus), NULL);
+       attach_label(w, 0, 1, 5, 6);
+       attach_entry(ntp_servers, 1, 2, 5, 6);
 
        hbox = gtk_hbox_new(FALSE, 0);
        gtk_box_pack_start(GTK_BOX(dialog_vbox), hbox, TRUE, TRUE, 3);
-       label = gtk_button_new_from_stock(GTK_STOCK_REDO);
-       gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
-       gtk_signal_connect(GTK_OBJECT(label), "clicked", on_redo, NULL);
-       label = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
-       gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 0);
-       gtk_signal_connect(GTK_OBJECT(label), "clicked",
-                          dhcpcd_prefs_close, NULL);
-
-       show_config(NULL, NULL);
+       w = gtk_button_new_from_stock(GTK_STOCK_CLEAR);
+       gtk_box_pack_start(GTK_BOX(hbox), w, FALSE, FALSE, 0);
+       g_signal_connect(G_OBJECT(w), "clicked", on_clear, NULL);
+       w = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
+       gtk_box_pack_end(GTK_BOX(hbox), w, FALSE, FALSE, 0);
+       g_signal_connect(G_OBJECT(w), "clicked",
+           dhcpcd_prefs_close, NULL);
+       
+       blocks_on_change(blocks);
+       show_config(NULL);
        gtk_widget_show_all(dialog);
 }