/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2013 Red Hat, Inc. */ /** * SECTION:nmt-ip-entry * @short_description: #NmtNewtEntry for IP address entry * * #NmtIPEntry is an #NmtNewtEntry for entering IP addresses, or IP * address/prefix combination. It will only allow typing characters * that are valid in an IP address, and will set its * #NmtNewtWidget:valid property depending on whether it currently * contains a valid IP address. */ #include "nm-default.h" #include #include #include #include "nmt-ip-entry.h" G_DEFINE_TYPE(NmtIPEntry, nmt_ip_entry, NMT_TYPE_NEWT_ENTRY) #define NMT_IP_ENTRY_GET_PRIVATE(o) \ (G_TYPE_INSTANCE_GET_PRIVATE((o), NMT_TYPE_IP_ENTRY, NmtIPEntryPrivate)) typedef struct { int family; gboolean prefix; gboolean optional; } NmtIPEntryPrivate; enum { PROP_0, PROP_FAMILY, PROP_PREFIX, PROP_OPTIONAL, LAST_PROP }; /** * nmt_ip_entry_new: * @width: the width of the entry * @family: the IP address family. Eg, %AF_INET * @prefix: whether to require a trailing "/prefix" * @optional: whether the address is optional * * Creates a new #NmtIPEntry, to accept IP addresses in the indicated * @family, or (if @prefix is %TRUE), to accept IP address/prefix combos. * * If @optional is %TRUE then the address is considered optional, and * so will still be #NmtNewtWidget:valid even when it is empty. If * @optional is %FALSE, the entry will be invalid when it is empty. */ NmtNewtWidget * nmt_ip_entry_new(int width, int family, gboolean prefix, gboolean optional) { return g_object_new(NMT_TYPE_IP_ENTRY, "width", width, "family", family, "prefix", prefix, "optional", optional, NULL); } static gboolean ip_entry_filter(NmtNewtEntry *entry, const char *text, int ch, int position, gpointer user_data) { NmtIPEntryPrivate *priv = NMT_IP_ENTRY_GET_PRIVATE(entry); const char * slash; gboolean inaddr; if (g_ascii_isdigit(ch)) return TRUE; slash = strchr(text, '/'); if (ch == '/') return priv->prefix && slash == NULL; inaddr = !slash || (position <= (slash - text)); if (priv->family == AF_INET) { if (ch == '.') return inaddr; else return FALSE; } else if (priv->family == AF_INET6) { if (g_ascii_isxdigit(ch) || ch == ':') return inaddr; else return FALSE; } else g_return_val_if_reached(FALSE); } static gboolean ip_entry_validate(NmtNewtEntry *entry, const char *text, gpointer user_data) { NmtIPEntryPrivate *priv = NMT_IP_ENTRY_GET_PRIVATE(entry); if (!*text) return priv->optional; if (priv->prefix) return nm_utils_parse_inaddr_prefix(priv->family, text, NULL, NULL); return nm_utils_parse_inaddr(priv->family, text, NULL); } static void nmt_ip_entry_init(NmtIPEntry *entry) { nmt_newt_entry_set_filter(NMT_NEWT_ENTRY(entry), ip_entry_filter, NULL); nmt_newt_entry_set_validator(NMT_NEWT_ENTRY(entry), ip_entry_validate, NULL); } static void nmt_ip_entry_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { NmtIPEntryPrivate *priv = NMT_IP_ENTRY_GET_PRIVATE(object); switch (prop_id) { case PROP_FAMILY: priv->family = g_value_get_int(value); break; case PROP_PREFIX: priv->prefix = g_value_get_boolean(value); break; case PROP_OPTIONAL: priv->optional = g_value_get_boolean(value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } static void nmt_ip_entry_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { NmtIPEntryPrivate *priv = NMT_IP_ENTRY_GET_PRIVATE(object); switch (prop_id) { case PROP_FAMILY: g_value_set_int(value, priv->family); break; case PROP_PREFIX: g_value_set_boolean(value, priv->prefix); break; case PROP_OPTIONAL: g_value_set_boolean(value, priv->optional); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } static void nmt_ip_entry_class_init(NmtIPEntryClass *entry_class) { GObjectClass *object_class = G_OBJECT_CLASS(entry_class); g_type_class_add_private(entry_class, sizeof(NmtIPEntryPrivate)); /* virtual methods */ object_class->set_property = nmt_ip_entry_set_property; object_class->get_property = nmt_ip_entry_get_property; /** * NmtIPEntry:family: * * The address family. Eg, %AF_INET */ g_object_class_install_property( object_class, PROP_FAMILY, g_param_spec_int("family", "", "", 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); /** * NmtIPEntry:prefix: * * If %TRUE, the entry accepts address/prefix combinations. If * %FALSE it accepts just addresses. */ g_object_class_install_property( object_class, PROP_PREFIX, g_param_spec_boolean("prefix", "", "", FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); /** * NmtIPEntry:optional: * * If %TRUE, the entry will be #NmtNewtWidget:valid when it is * empty. If %FALSE, it will only be valid when it contains a * valid address or address/prefix. */ g_object_class_install_property( object_class, PROP_OPTIONAL, g_param_spec_boolean("optional", "", "", FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); }