Index: src/setup/gnunet-setup.c =================================================================== --- src/setup/gnunet-setup.c (revision 19067) +++ src/setup/gnunet-setup.c (working copy) @@ -171,6 +171,8 @@ os->widget_name); return; } + if (NULL != os->input_validation_function) + os->input_validation_function (os->input_validation_function_cls, widget); if ((os->section != NULL) && (os->option != NULL)) GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, os->section, @@ -246,6 +248,8 @@ } } } + if (NULL != os->input_validation_function) + os->input_validation_function (os->input_validation_function_cls, widget); if (os->help_text != NULL) { g_signal_connect (widget, "button-press-event", Index: src/setup/gnunet-setup-options.c =================================================================== --- src/setup/gnunet-setup-options.c (revision 19067) +++ src/setup/gnunet-setup-options.c (working copy) @@ -38,8 +38,38 @@ */ #define REX_NO "^NO$" +/** + * Color for marking invalid input + */ +#define INVALID_INPUT_COLOR "red" + /** + * Structs of this type specify connection between widgets storing + * port numbers and widgets controlling status of respective transport. + */ +struct PortSpecification +{ + /** + * Name of the GtkSpinButton storing the port value. + */ + const char *spinbutton_name; + + /** + * Name of the GtkCheckButton controlling whether the respective + * transport/daemon is enabled. + */ + const char *checkbutton_name; + + /** + * Name of the transport/daemon which owns this port. + */ + const char *owner_name; + +}; + + +/** * Initialize a toggle button based on an options 'yes/no' value. * * @param cls closure @@ -312,6 +342,159 @@ /** + * NULL-terminated list of port specifications, which should be checked + * for collisions. + */ +static struct PortSpecification port_specifications[] = { + { + "GNUNET_setup_hostlist_server_port_spin_button", + "GNUNET_setup_hostlist_offer_hostlist_checkbutton", + gettext_noop ("the hostlist server"),}, + { + "GNUNET_setup_transport_tcp_port_spinbutton", + "GNUNET_setup_transport_tcp_checkbutton", + gettext_noop ("the TCP transport plugin"),}, + { + "GNUNET_setup_transport_http_port_spinbutton", + "GNUNET_setup_transport_http_checkbutton", + gettext_noop ("the HTTP transport plugin"),}, + { + "GNUNET_setup_transport_https_port_spinbutton", + "GNUNET_setup_transport_https_checkbutton", + gettext_noop ("the HTTPS transport plugin"),}, + {NULL, NULL} +}; + + +/** + * Find spinbutton associated with a port specification. + * + * @param i index of the respective port specification + * @return spinbutton or NULL in case of an error or if respecitve transport is disabled + */ +static GtkSpinButton * +get_port_spinbutton (unsigned int i) +{ + const char *sb_name; + const char *cb_name; + GtkWidget *widget; + GtkToggleButton *checkbt; + GtkSpinButton *spinbt; + gboolean mode; + + if (port_specifications[i].spinbutton_name == NULL || + port_specifications[i].checkbutton_name == NULL) + return NULL; + cb_name = port_specifications[i].checkbutton_name; + widget = GTK_WIDGET (GNUNET_SETUP_get_object (cb_name)); + if (widget == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Widget `%s' not found\n"), + cb_name); + return NULL; + } + checkbt = GTK_TOGGLE_BUTTON (widget); + if (checkbt == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Specified widget `%s' is not a checkbutton\n"), + cb_name); + return NULL; + } + mode = gtk_toggle_button_get_active (checkbt); + if (TRUE != mode) + return NULL; + + sb_name = port_specifications[i].spinbutton_name; + widget = GTK_WIDGET (GNUNET_SETUP_get_object (sb_name)); + if (widget == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Widget `%s' not found\n"), + sb_name); + return NULL; + } + spinbt = GTK_SPIN_BUTTON (widget); + if (spinbt == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Specified widget `%s' is not a spinbutton\n"), + sb_name); + return NULL; + } + return spinbt; +} + + +/** + * Check port numbers for collisions and highlight conflicting ports, if any. + * + * @param cls closure (unused) + * @param widget widget whose state was changed (unused) + */ +static void +highlight_port_collisions (const void *cls, + GObject *widget) +{ + unsigned int i; + unsigned int j; + unsigned int port; + GtkSpinButton *spinbt_i; + GtkSpinButton *spinbt_j; + GdkColor color; + GdkColor *pcolor; + int found; + char *tooltip; + + gdk_color_parse (INVALID_INPUT_COLOR, &color); + for (i = 0; + port_specifications[i].spinbutton_name != NULL; + i++) + { + spinbt_i = get_port_spinbutton (i); + if (spinbt_i == NULL) + continue; + else + port = gtk_spin_button_get_value_as_int (spinbt_i); + + found = GNUNET_NO; + for (j = 0; + port_specifications[j].spinbutton_name != NULL; + j++) + { + if (i == j) continue; + spinbt_j = get_port_spinbutton (j); + if (spinbt_j == NULL) + continue; + if (port == gtk_spin_button_get_value_as_int (spinbt_j)) + { + found = GNUNET_YES; + break; + } + } + if (GNUNET_YES == found) + { + pcolor = &color; + GNUNET_asprintf (&tooltip, _("This port is already occupied by %s."), + port_specifications[j].owner_name); + } + else + { + pcolor = NULL; + tooltip = GNUNET_strdup (""); + } + gtk_widget_modify_text (GTK_WIDGET (spinbt_i), + GTK_STATE_NORMAL, pcolor); + gtk_widget_modify_text (GTK_WIDGET (spinbt_i), + GTK_STATE_ACTIVE, pcolor); + gtk_widget_modify_text (GTK_WIDGET (spinbt_i), + GTK_STATE_SELECTED, pcolor); + gtk_widget_set_tooltip_text (GTK_WIDGET (spinbt_i), tooltip); + GNUNET_free (tooltip); + } +} + + +/** * Initialize a toggle button based on the existence of a word * in an option value. * @@ -1465,6 +1648,7 @@ "https://gnunet.org/configuration-f2f", &load_yes_no, &save_yes_no, NULL, + NULL, NULL, hide_min_connected_friends}, { @@ -1476,6 +1660,7 @@ "https://gnunet.org/configuration-f2f", &load_filename, &save_filename, NULL, + NULL, NULL, NULL}, { @@ -1487,6 +1672,7 @@ "https://gnunet.org/configuration-f2f", &load_number, &save_number, NULL, + NULL, NULL, NULL}, { @@ -1498,6 +1684,7 @@ "https://gnunet.org/configuration-topology", &load_option_list, &save_option_list, "topology", + NULL, NULL, NULL}, { @@ -1510,6 +1697,7 @@ "https://gnunet.org/configuration-hostlist", &load_option_list, &save_option_list, "hostlist", + NULL, NULL, hide_hostlist_options}, @@ -1522,6 +1710,7 @@ "https://gnunet.org/configuration-fs", &load_option_list, &save_option_list, "fs", + NULL, NULL, hide_fs_tab}, { @@ -1533,6 +1722,7 @@ "https://gnunet.org/configuration-vpn", &load_option_list, &save_option_list, "vpn", + NULL, NULL, hide_vpn_tab}, { @@ -1544,6 +1734,7 @@ "https://gnunet.org/configuration-hostlist", &load_option_list, &save_option_list, "-b", + NULL, NULL, NULL}, { @@ -1555,6 +1746,7 @@ "https://gnunet.org/configuration-hostlist", &load_option_list, &save_option_list, "-e", + NULL, NULL, NULL}, { @@ -1566,6 +1758,7 @@ "https://gnunet.org/configuration-hostlist-server", &load_option_list, &save_option_list, "-p", + &highlight_port_collisions, NULL, hide_hostlist_server_options}, { @@ -1577,6 +1770,7 @@ "https://gnunet.org/configuration-hostlist-server", &load_option_list, &save_option_list, "-a", + NULL, NULL, NULL}, { @@ -1588,6 +1782,7 @@ "https://gnunet.org/configuration-hostlist-server", &load_number, &save_number, NULL, + &highlight_port_collisions, NULL, NULL}, { @@ -1598,6 +1793,7 @@ NULL, NULL, &load_string_list_store, &save_string_list_store, NULL, + NULL, NULL, NULL}, { @@ -1606,6 +1802,7 @@ gettext_noop ("Known hostlist URLs"), "https://gnunet.org/configuration-hostlist", NULL, NULL, NULL, /* FIXME */ + NULL, NULL, NULL}, { @@ -1617,6 +1814,7 @@ "https://gnunet.org/configuration-bandwidth", &load_number, &save_number, NULL, + NULL, NULL, NULL}, { @@ -1628,6 +1826,7 @@ "https://gnunet.org/configuration-bandwidth", &load_number, &save_number, NULL, + NULL, NULL, NULL}, /* Transport TAB */ @@ -1641,6 +1840,7 @@ "https://gnunet.org/configuration-tcp", &load_option_list, &save_option_list, "tcp", + &highlight_port_collisions, NULL, hide_tcp_tab}, { @@ -1652,6 +1852,7 @@ "https://gnunet.org/configuration-udp", &load_option_list, &save_option_list, "udp", + NULL, NULL, hide_udp_tab}, { @@ -1663,6 +1864,7 @@ "https://gnunet.org/configuration-http", &load_option_list, &save_option_list, "http", + &highlight_port_collisions, NULL, hide_http_tab}, { @@ -1674,6 +1876,7 @@ "https://gnunet.org/configuration-https", &load_option_list, &save_option_list, "https", + &highlight_port_collisions, NULL, hide_https_tab}, { @@ -1685,6 +1888,7 @@ "https://gnunet.org/configuration-dv", &load_option_list, &save_option_list, "dv", + NULL, NULL, hide_dv_tab}, { @@ -1696,6 +1900,7 @@ "https://gnunet.org/configuration-wlan", &load_option_list, &save_option_list, "wlan", + NULL, NULL, hide_wlan_tab}, { @@ -1707,6 +1912,7 @@ "https://gnunet.org/configuration-tcp", &load_number, &save_number, NULL, + &highlight_port_collisions, NULL, hide_all_tcp_options}, { @@ -1718,6 +1924,7 @@ "https://gnunet.org/configuration-tcp", &load_number, &save_number, NULL, + NULL, NULL, NULL}, { @@ -1729,6 +1936,7 @@ "https://gnunet.org/configuration-nat", &load_yes_no, &save_yes_no, NULL, + NULL, NULL, toggle_nat_options}, { @@ -1740,6 +1948,7 @@ "https://gnunet.org/configuration-nat", &load_yes_no, &save_yes_no, NULL, + NULL, NULL, toggle_nat_punched_options}, { @@ -1751,6 +1960,7 @@ "https://gnunet.org/configuration-nat", &load_yes_no, &save_yes_no, NULL, + NULL, NULL, NULL, }, @@ -1763,6 +1973,7 @@ "https://gnunet.org/configuration-nat", &load_yes_no, &save_yes_no, NULL, + NULL, NULL, NULL, }, @@ -1775,6 +1986,7 @@ "https://gnunet.org/configuration-nat", &load_text, &save_text, NULL, + NULL, NULL, NULL}, { @@ -1786,6 +1998,7 @@ "https://gnunet.org/configuration-nat", &load_yes_no, &save_yes_no, NULL, + NULL, NULL, toggle_internal_ip}, { @@ -1797,6 +2010,7 @@ "https://gnunet.org/configuration-nat", &load_text, &save_text, NULL, + NULL, NULL, NULL}, { @@ -1808,6 +2022,7 @@ "https://gnunet.org/configuration-ipv6", &load_yes_no, &save_yes_no, NULL, + NULL, NULL, NULL, }, @@ -1820,6 +2035,7 @@ "https://gnunet.org/configuration-udp", &load_number, &save_number, NULL, + NULL, NULL, NULL}, { @@ -1831,6 +2047,7 @@ "https://gnunet.org/configuration-http", &load_number, &save_number, NULL, + &highlight_port_collisions, NULL, NULL}, { @@ -1842,6 +2059,7 @@ "https://gnunet.org/configuration-https", &load_number, &save_number, NULL, + &highlight_port_collisions, NULL, NULL}, /* FS TAB */ @@ -1855,6 +2073,7 @@ "https://gnunet.org/configuration-datastore", &load_option_list /* abuse! */ , &save_option_list /* abuse! */ , "sqlite", + NULL, NULL, hide_sqlite_datastore_tab}, { @@ -1866,6 +2085,7 @@ "https://gnunet.org/configuration-datastore", &load_option_list /* abuse! */ , &save_option_list /* abuse! */ , "mysql", + NULL, NULL, hide_mysql_datastore_tab}, { @@ -1877,6 +2097,7 @@ "https://gnunet.org/configuration-datastore", &load_option_list /* abuse! */ , &save_option_list /* abuse! */ , "postgres", + NULL, NULL, hide_postgres_datastore_tab}, { @@ -1888,6 +2109,7 @@ "https://gnunet.org/configuration-datastore", &load_text, &save_text, NULL, + NULL, NULL, NULL}, { @@ -1899,6 +2121,7 @@ "http://dev.mysql.com/doc/refman/5.5/en/option-files.html", &load_filename, &save_filename, NULL, + NULL, NULL, NULL}, { @@ -1910,6 +2133,7 @@ "https://gnunet.org/configuration-datastore", &load_text, &save_text, NULL, + NULL, NULL, NULL}, { @@ -1921,6 +2145,7 @@ "https://gnunet.org/configuration-datastore", &load_text, &save_text, NULL, + NULL, NULL, NULL}, { @@ -1932,6 +2157,7 @@ "https://gnunet.org/configuration-datastore", &load_text, &save_text, NULL, + NULL, NULL, NULL}, { @@ -1943,6 +2169,7 @@ "https://gnunet.org/configuration-datastore", &load_number, &save_number, NULL, + NULL, NULL, NULL}, { @@ -1954,6 +2181,7 @@ "http://www.postgresql.org/docs/8.1/static/libpq.html#LIBPQ-CONNECT", &load_text, &save_text, NULL, + NULL, NULL, NULL}, @@ -1966,6 +2194,7 @@ "https://gnunet.org/configuration-fs", &load_yes_no, &save_yes_no, NULL, + NULL, NULL, NULL}, { @@ -1977,6 +2206,7 @@ "https://gnunet.org/configuration-fs", &load_yes_no, &save_yes_no, NULL, + NULL, NULL, NULL}, { @@ -1988,6 +2218,7 @@ "https://gnunet.org/configuration-datacache", &load_option_list /* abuse! */ , &save_option_list /* abuse! */ , "sqlite", + NULL, NULL, hide_sqlite_datacache_tab}, { @@ -1999,6 +2230,7 @@ "https://gnunet.org/configuration-datacache", &load_option_list /* abuse! */ , &save_option_list /* abuse! */ , "mysql", + NULL, NULL, hide_mysql_datacache_tab}, { @@ -2010,6 +2242,7 @@ "https://gnunet.org/configuration-datacache", &load_option_list /* abuse! */ , &save_option_list /* abuse! */ , "postgres", + NULL, NULL, hide_postgres_datacache_tab}, { @@ -2021,6 +2254,7 @@ "https://gnunet.org/configuration-datacache", &load_text, &save_text, NULL, + NULL, NULL, NULL}, { @@ -2032,6 +2266,7 @@ "http://dev.mysql.com/doc/refman/5.5/en/option-files.html", &load_filename, &save_filename, NULL, + NULL, NULL, NULL}, { @@ -2043,6 +2278,7 @@ "https://gnunet.org/configuration-datacache", &load_text, &save_text, NULL, + NULL, NULL, NULL}, { @@ -2054,6 +2290,7 @@ "https://gnunet.org/configuration-datacache", &load_text, &save_text, NULL, + NULL, NULL, NULL}, { @@ -2065,6 +2302,7 @@ "https://gnunet.org/configuration-datacache", &load_text, &save_text, NULL, + NULL, NULL, NULL}, { @@ -2076,6 +2314,7 @@ "https://gnunet.org/configuration-wlan", &load_text, &save_text, NULL, + NULL, NULL, NULL}, { @@ -2087,6 +2326,7 @@ "https://gnunet.org/configuration-datacache", &load_number, &save_number, NULL, + NULL, NULL, NULL}, { @@ -2098,6 +2338,7 @@ "http://www.postgresql.org/docs/8.1/static/libpq.html#LIBPQ-CONNECT", &load_text, &save_text, NULL, + NULL, NULL, NULL}, { @@ -2109,6 +2350,7 @@ "https://gnunet.org/configuration-vpn", &load_text, &save_text, NULL, + NULL, NULL, NULL}, { @@ -2120,6 +2362,7 @@ "https://gnunet.org/configuration-vpn", &load_text, &save_text, NULL, + NULL, NULL, NULL}, { @@ -2131,6 +2374,7 @@ "https://gnunet.org/configuration-vpn", &load_text, &save_text, NULL, + NULL, NULL, NULL}, { @@ -2142,6 +2386,7 @@ "https://gnunet.org/configuration-vpn", &load_text, &save_text, NULL, + NULL, NULL, NULL}, { @@ -2153,6 +2398,7 @@ "https://gnunet.org/configuration-vpn", &load_number, &save_number, NULL, + NULL, NULL, NULL}, { @@ -2165,6 +2411,7 @@ "https://gnunet.org/configuration-vpn", &load_text, &save_text, NULL, + NULL, NULL, NULL}, { @@ -2177,6 +2424,7 @@ "https://gnunet.org/configuration-exit", &load_option_list, &save_option_list, "exit", + NULL, NULL, hide_exit_options}, { @@ -2189,6 +2437,7 @@ "https://gnunet.org/configuration-dns", &load_yes_no, &save_yes_no, NULL, + NULL, NULL, NULL}, { @@ -2201,6 +2450,7 @@ "https://gnunet.org/configuration-exit", &load_text, &save_text, NULL, + NULL, NULL, NULL}, { @@ -2212,6 +2462,7 @@ "https://gnunet.org/configuration-exit", &load_text, &save_text, NULL, + NULL, NULL, NULL}, { @@ -2223,6 +2474,7 @@ "https://gnunet.org/configuration-exit", &load_text, &save_text, NULL, + NULL, NULL, NULL}, { @@ -2234,6 +2486,7 @@ "https://gnunet.org/configuration-exit", &load_text, &save_text, NULL, + NULL, NULL, NULL}, { @@ -2246,6 +2499,7 @@ "https://gnunet.org/configuration-exit", &load_number, &save_number, NULL, + NULL, NULL, NULL}, @@ -2259,6 +2513,7 @@ "https://gnunet.org/configuration-exit", &load_yes_no, &save_yes_no, NULL, + NULL, NULL, NULL}, { @@ -2271,6 +2526,7 @@ "https://gnunet.org/configuration-exit", &load_yes_no, &save_yes_no, NULL, + NULL, NULL, NULL}, /* DNS treeview */ @@ -2285,6 +2541,7 @@ "https://gnunet.org/configuration-dns", &load_vpn_dns_configuration, NULL, NULL, + NULL, NULL, NULL}, { @@ -2297,6 +2554,8 @@ NULL, &vpn_dns_service_dnsname_install_edited_handler, NULL, + NULL, + NULL, NULL}, { @@ -2309,6 +2568,8 @@ NULL, &vpn_dns_service_tcpudp_install_edited_handler, NULL, + NULL, + NULL, NULL}, { @@ -2321,6 +2582,8 @@ NULL, &vpn_dns_service_sourceport_install_edited_handler, NULL, + NULL, + NULL, NULL}, { @@ -2333,6 +2596,8 @@ NULL, &vpn_dns_service_targethostname_install_edited_handler, NULL, + NULL, + NULL, NULL}, { @@ -2345,12 +2610,15 @@ NULL, &vpn_dns_service_targetport_install_edited_handler, NULL, + NULL, + NULL, NULL}, /* END of list */ {NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL} + NULL, NULL, NULL, NULL, NULL, + NULL} }; /* end of gnunet-setup-options.c */ Index: src/setup/gnunet-setup-options.h =================================================================== --- src/setup/gnunet-setup-options.h (revision 19067) +++ src/setup/gnunet-setup-options.h (working copy) @@ -65,6 +65,17 @@ /** + * Function called each time the widget changes its state to validate + * its value. + * + * @param cls closure + * @param widget widget whose state was changed + */ +typedef void (*GNUNET_SETUP_InputValidationFunction) (const void *cls, + GObject *widget); + + +/** * Structs of this type specify under which conditions the values of * a particular option impact the visibility (or sensitivity) of some * other widget. @@ -143,6 +154,16 @@ const void *load_save_cls; /** + * Function to call to validate the value of the widget. + */ + GNUNET_SETUP_InputValidationFunction input_validation_function; + + /** + * Closure for 'input_validation_function'. + */ + const void *input_validation_function_cls; + + /** * Visibility changes to apply if this option changes (NULL, or * NULL-terminated). */