Blame src/utils/utils.c

Packit Service 639700
// SPDX-License-Identifier: GPL-2.0+
Packit fabffb
/* NetworkManager Applet -- allow user control over networking
Packit fabffb
 *
Packit fabffb
 * Dan Williams <dcbw@redhat.com>
Packit fabffb
 *
Packit fabffb
 * Copyright 2007 - 2015 Red Hat, Inc.
Packit fabffb
 */
Packit fabffb
Packit fabffb
#include "nm-default.h"
Packit fabffb
Packit fabffb
#include "utils.h"
Packit fabffb
Packit fabffb
#include <string.h>
Packit fabffb
#include <errno.h>
Packit fabffb
#include <arpa/inet.h>
Packit fabffb
#include <netinet/ether.h>
Packit fabffb
Packit fabffb
#include "nm-utils.h"
Packit fabffb
#include "nm-utils/nm-shared-utils.h"
Packit fabffb
Packit fabffb
/*
Packit fabffb
 * utils_ether_addr_valid
Packit fabffb
 *
Packit fabffb
 * Compares an Ethernet address against known invalid addresses.
Packit fabffb
 *
Packit fabffb
 */
Packit fabffb
gboolean
Packit fabffb
utils_ether_addr_valid (const struct ether_addr *test_addr)
Packit fabffb
{
Packit fabffb
	guint8 invalid_addr1[ETH_ALEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
Packit fabffb
	guint8 invalid_addr2[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
Packit fabffb
	guint8 invalid_addr3[ETH_ALEN] = {0x44, 0x44, 0x44, 0x44, 0x44, 0x44};
Packit fabffb
	guint8 invalid_addr4[ETH_ALEN] = {0x00, 0x30, 0xb4, 0x00, 0x00, 0x00}; /* prism54 dummy MAC */
Packit fabffb
Packit fabffb
	g_return_val_if_fail (test_addr != NULL, FALSE);
Packit fabffb
Packit fabffb
	/* Compare the AP address the card has with invalid ethernet MAC addresses. */
Packit fabffb
	if (!memcmp (test_addr->ether_addr_octet, &invalid_addr1, ETH_ALEN))
Packit fabffb
		return FALSE;
Packit fabffb
Packit fabffb
	if (!memcmp (test_addr->ether_addr_octet, &invalid_addr2, ETH_ALEN))
Packit fabffb
		return FALSE;
Packit fabffb
Packit fabffb
	if (!memcmp (test_addr->ether_addr_octet, &invalid_addr3, ETH_ALEN))
Packit fabffb
		return FALSE;
Packit fabffb
Packit fabffb
	if (!memcmp (test_addr->ether_addr_octet, &invalid_addr4, ETH_ALEN))
Packit fabffb
		return FALSE;
Packit fabffb
Packit fabffb
	if (test_addr->ether_addr_octet[0] & 1)			/* Multicast addresses */
Packit fabffb
		return FALSE;
Packit fabffb
Packit fabffb
	return TRUE;
Packit fabffb
}
Packit fabffb
Packit fabffb
char *
Packit Service 639700
utils_hash_ap (GBytes *ssid,
Packit fabffb
               NM80211Mode mode,
Packit fabffb
               guint32 flags,
Packit fabffb
               guint32 wpa_flags,
Packit fabffb
               guint32 rsn_flags)
Packit fabffb
{
Packit fabffb
	unsigned char input[66];
Packit fabffb
Packit fabffb
	memset (&input[0], 0, sizeof (input));
Packit fabffb
Packit Service 639700
	if (ssid)
Packit fabffb
		memcpy (input, g_bytes_get_data (ssid, NULL), g_bytes_get_size (ssid));
Packit fabffb
Packit fabffb
	if (mode == NM_802_11_MODE_INFRA)
Packit fabffb
		input[32] |= (1 << 0);
Packit fabffb
	else if (mode == NM_802_11_MODE_ADHOC)
Packit fabffb
		input[32] |= (1 << 1);
Packit fabffb
	else
Packit fabffb
		input[32] |= (1 << 2);
Packit fabffb
Packit fabffb
	/* Separate out no encryption, WEP-only, and WPA-capable */
Packit fabffb
	if (  !(flags & NM_802_11_AP_FLAGS_PRIVACY)
Packit fabffb
	    && (wpa_flags == NM_802_11_AP_SEC_NONE)
Packit fabffb
	    && (rsn_flags == NM_802_11_AP_SEC_NONE))
Packit fabffb
		input[32] |= (1 << 3);
Packit fabffb
	else if (   (flags & NM_802_11_AP_FLAGS_PRIVACY)
Packit fabffb
	         && (wpa_flags == NM_802_11_AP_SEC_NONE)
Packit fabffb
	         && (rsn_flags == NM_802_11_AP_SEC_NONE))
Packit fabffb
		input[32] |= (1 << 4);
Packit fabffb
	else if (   !(flags & NM_802_11_AP_FLAGS_PRIVACY)
Packit fabffb
	         &&  (wpa_flags != NM_802_11_AP_SEC_NONE)
Packit fabffb
	         &&  (rsn_flags != NM_802_11_AP_SEC_NONE))
Packit fabffb
		input[32] |= (1 << 5);
Packit fabffb
	else
Packit fabffb
		input[32] |= (1 << 6);
Packit fabffb
Packit fabffb
	/* duplicate it */
Packit fabffb
	memcpy (&input[33], &input[0], 32);
Packit fabffb
	return g_compute_checksum_for_data (G_CHECKSUM_MD5, input, sizeof (input));
Packit fabffb
}
Packit fabffb
Packit fabffb
typedef struct {
Packit fabffb
	const char *tag;
Packit fabffb
	const char *replacement;
Packit fabffb
} Tag;
Packit fabffb
Packit fabffb
static Tag escaped_tags[] = {
Packit fabffb
	{ "<center>", NULL },
Packit fabffb
	{ "</center>", NULL },
Packit fabffb
	{ "

", "\n" },

Packit fabffb
	{ "

", NULL },
Packit fabffb
	{ "", "" },
Packit fabffb
	{ "", "" },
Packit fabffb
	{ "", "" },
Packit fabffb
	{ "", "" },
Packit fabffb
	{ "<u>", "<u>" },
Packit fabffb
	{ "</u>", "</u>" },
Packit fabffb
	{ "&", "&" },
Packit fabffb
	{ NULL, NULL }
Packit fabffb
};
Packit fabffb
Packit fabffb
char *
Packit fabffb
utils_escape_notify_message (const char *src)
Packit fabffb
{
Packit fabffb
	const char *p = src;
Packit fabffb
	GString *escaped;
Packit fabffb
Packit fabffb
	/* Filter the source text and get rid of some HTML tags since the
Packit fabffb
	 * notification spec only allows a subset of HTML.  Substitute
Packit fabffb
	 * HTML code for characters like & that are invalid in HTML.
Packit fabffb
	 */
Packit fabffb
Packit fabffb
	escaped = g_string_sized_new (strlen (src) + 5);
Packit fabffb
	while (*p) {
Packit fabffb
		Tag *t = &escaped_tags[0];
Packit fabffb
		gboolean found = FALSE;
Packit fabffb
Packit fabffb
		while (t->tag) {
Packit fabffb
			if (strncasecmp (p, t->tag, strlen (t->tag)) == 0) {
Packit fabffb
				p += strlen (t->tag);
Packit fabffb
				if (t->replacement)
Packit fabffb
					g_string_append (escaped, t->replacement);
Packit fabffb
				found = TRUE;
Packit fabffb
				break;
Packit fabffb
			}
Packit fabffb
			t++;
Packit fabffb
		}
Packit fabffb
		if (!found)
Packit fabffb
			g_string_append_c (escaped, *p++);
Packit fabffb
	}
Packit fabffb
Packit fabffb
	return g_string_free (escaped, FALSE);
Packit fabffb
}
Packit fabffb
Packit fabffb
char *
Packit fabffb
utils_create_mobile_connection_id (const char *provider, const char *plan_name)
Packit fabffb
{
Packit fabffb
	g_return_val_if_fail (provider != NULL, NULL);
Packit fabffb
Packit fabffb
	if (plan_name)
Packit fabffb
		return g_strdup_printf ("%s %s", provider, plan_name);
Packit fabffb
Packit fabffb
	/* The %s is a mobile provider name, eg "T-Mobile" */
Packit fabffb
	return g_strdup_printf (_("%s connection"), provider);
Packit fabffb
}
Packit fabffb
Packit fabffb
void
Packit fabffb
utils_show_error_dialog (const char *title,
Packit fabffb
                         const char *text1,
Packit fabffb
                         const char *text2,
Packit fabffb
                         gboolean modal,
Packit fabffb
                         GtkWindow *parent)
Packit fabffb
{
Packit fabffb
	GtkWidget *err_dialog;
Packit fabffb
Packit fabffb
	g_return_if_fail (text1 != NULL);
Packit fabffb
Packit fabffb
	err_dialog = gtk_message_dialog_new (parent,
Packit fabffb
	                                     GTK_DIALOG_DESTROY_WITH_PARENT,
Packit fabffb
	                                     GTK_MESSAGE_ERROR,
Packit fabffb
	                                     GTK_BUTTONS_CLOSE,
Packit fabffb
	                                     "%s",
Packit fabffb
	                                     text1);
Packit fabffb
Packit fabffb
	gtk_window_set_position (GTK_WINDOW (err_dialog), GTK_WIN_POS_CENTER_ALWAYS);
Packit fabffb
Packit fabffb
	if (text2)
Packit fabffb
		gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (err_dialog), "%s", text2);
Packit fabffb
	if (title)
Packit fabffb
		gtk_window_set_title (GTK_WINDOW (err_dialog), title);
Packit fabffb
Packit fabffb
	if (modal) {
Packit fabffb
		gtk_dialog_run (GTK_DIALOG (err_dialog));
Packit fabffb
		gtk_widget_destroy (err_dialog);
Packit fabffb
	} else {
Packit fabffb
		g_signal_connect (err_dialog, "delete-event", G_CALLBACK (gtk_widget_destroy), NULL);
Packit fabffb
		g_signal_connect (err_dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
Packit fabffb
Packit fabffb
		gtk_widget_show (err_dialog);
Packit fabffb
		gtk_window_present (GTK_WINDOW (err_dialog));
Packit fabffb
	}
Packit fabffb
}
Packit fabffb
Packit fabffb
Packit fabffb
gboolean
Packit fabffb
utils_char_is_ascii_print (char character)
Packit fabffb
{
Packit fabffb
	return g_ascii_isprint (character);
Packit fabffb
}
Packit fabffb
Packit fabffb
gboolean
Packit fabffb
utils_char_is_ascii_digit (char character)
Packit fabffb
{
Packit fabffb
	return g_ascii_isdigit (character);
Packit fabffb
}
Packit fabffb
Packit fabffb
gboolean
Packit fabffb
utils_char_is_ascii_ip4_address (char character)
Packit fabffb
{
Packit fabffb
	return g_ascii_isdigit (character) || character == '.';
Packit fabffb
}
Packit fabffb
Packit fabffb
gboolean
Packit fabffb
utils_char_is_ascii_ip6_address (char character)
Packit fabffb
{
Packit fabffb
	return g_ascii_isxdigit (character) || character == ':';
Packit fabffb
}
Packit fabffb
Packit fabffb
gboolean
Packit fabffb
utils_char_is_ascii_apn (char character)
Packit fabffb
{
Packit fabffb
	return g_ascii_isalnum (character)
Packit fabffb
	       || character == '.'
Packit fabffb
	       || character == '_'
Packit fabffb
	       || character == '-';
Packit fabffb
}
Packit fabffb
Packit fabffb
/**
Packit fabffb
 * Filters the characters from a text that was just input into GtkEditable.
Packit fabffb
 * Returns FALSE, if after filtering no characters were left. TRUE means,
Packit fabffb
 * that valid characters were added and the content of the GtkEditable changed.
Packit fabffb
 **/
Packit fabffb
gboolean
Packit fabffb
utils_filter_editable_on_insert_text (GtkEditable *editable,
Packit fabffb
                                      const gchar *text,
Packit fabffb
                                      gint length,
Packit fabffb
                                      gint *position,
Packit fabffb
                                      void *user_data,
Packit fabffb
                                      UtilsFilterGtkEditableFunc validate_character,
Packit fabffb
                                      gpointer block_func)
Packit fabffb
{
Packit fabffb
	int i, count = 0;
Packit fabffb
	gchar *result = g_new (gchar, length+1);
Packit fabffb
Packit fabffb
	for (i = 0; i < length; i++) {
Packit fabffb
		if (validate_character (text[i]))
Packit fabffb
			result[count++] = text[i];
Packit fabffb
	}
Packit fabffb
	result[count] = 0;
Packit fabffb
Packit fabffb
	if (count > 0) {
Packit fabffb
		if (block_func) {
Packit fabffb
			g_signal_handlers_block_by_func (G_OBJECT (editable),
Packit fabffb
			                                 G_CALLBACK (block_func),
Packit fabffb
			                                 user_data);
Packit fabffb
		}
Packit fabffb
		gtk_editable_insert_text (editable, result, count, position);
Packit fabffb
		if (block_func) {
Packit fabffb
			g_signal_handlers_unblock_by_func (G_OBJECT (editable),
Packit fabffb
			                                   G_CALLBACK (block_func),
Packit fabffb
			                                   user_data);
Packit fabffb
		}
Packit fabffb
	}
Packit fabffb
	g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text");
Packit fabffb
Packit fabffb
	g_free (result);
Packit fabffb
Packit fabffb
	return count > 0;
Packit fabffb
}
Packit fabffb
Packit fabffb
/**
Packit fabffb
 * utils_override_bg_color:
Packit fabffb
 *
Packit fabffb
 * The function can be used to set background color for a widget.
Packit fabffb
 * There are functions for that in Gtk2 [1] and Gtk3 [2]. Unfortunately, they
Packit fabffb
 * have been deprecated, and moreover gtk_widget_override_background_color()
Packit fabffb
 * stopped working at some point for some Gtk themes, including the default
Packit fabffb
 * Adwaita theme.
Packit fabffb
 * [1] gtk_widget_modify_bg() or gtk_widget_modify_base()
Packit fabffb
 * [2] gtk_widget_override_background_color()
Packit fabffb
 *
Packit fabffb
 * Related links:
Packit fabffb
 * https://bugzilla.gnome.org/show_bug.cgi?id=656461
Packit fabffb
 * https://mail.gnome.org/archives/gtk-list/2015-February/msg00053.html
Packit fabffb
 */
Packit fabffb
void
Packit fabffb
utils_override_bg_color (GtkWidget *widget, GdkRGBA *rgba)
Packit fabffb
{
Packit fabffb
	GtkCssProvider *provider;
Packit fabffb
	char *css;
Packit fabffb
Packit fabffb
	provider = (GtkCssProvider *) g_object_get_data (G_OBJECT (widget), "our-css-provider");
Packit fabffb
	if (G_UNLIKELY (!provider)) {
Packit fabffb
		provider = gtk_css_provider_new ();
Packit fabffb
		gtk_style_context_add_provider (gtk_widget_get_style_context (widget),
Packit fabffb
		                                GTK_STYLE_PROVIDER (provider),
Packit fabffb
		                                GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
Packit fabffb
		g_object_set_data_full (G_OBJECT (widget), "our-css-provider",
Packit fabffb
		                        provider, (GDestroyNotify) g_object_unref);
Packit fabffb
	}
Packit fabffb
Packit fabffb
	if (rgba) {
Packit fabffb
		css = g_strdup_printf ("* { background-color: %s; background-image: none; }",
Packit fabffb
		                       gdk_rgba_to_string (rgba));
Packit Service 639700
#if GTK_CHECK_VERSION(3,90,0)
Packit Service 639700
		gtk_css_provider_load_from_data (provider, css, -1);
Packit Service 639700
#else
Packit fabffb
		gtk_css_provider_load_from_data (provider, css, -1, NULL);
Packit Service 639700
#endif
Packit fabffb
		g_free (css);
Packit Service 639700
	} else {
Packit Service 639700
#if GTK_CHECK_VERSION(3,90,0)
Packit Service 639700
		gtk_css_provider_load_from_data (provider, "", -1);
Packit Service 639700
#else
Packit fabffb
		gtk_css_provider_load_from_data (provider, "", -1, NULL);
Packit Service 639700
#endif
Packit Service 639700
	}
Packit fabffb
}
Packit fabffb
Packit fabffb
void
Packit fabffb
utils_set_cell_background (GtkCellRenderer *cell,
Packit fabffb
                           const char *color,
Packit fabffb
                           const char *value)
Packit fabffb
{
Packit fabffb
	if (color) {
Packit fabffb
		if (!value || !*value) {
Packit fabffb
			g_object_set (G_OBJECT (cell),
Packit fabffb
			              "cell-background-set", TRUE,
Packit fabffb
			              "cell-background", color,
Packit fabffb
			              NULL);
Packit fabffb
		} else {
Packit fabffb
			char *markup;
Packit fabffb
			markup = g_markup_printf_escaped ("%s",
Packit fabffb
			                                  color, value);
Packit fabffb
			g_object_set (G_OBJECT (cell), "markup", markup, NULL);
Packit fabffb
			g_free (markup);
Packit fabffb
			g_object_set (G_OBJECT (cell), "cell-background-set", FALSE, NULL);
Packit fabffb
		}
Packit fabffb
	} else
Packit fabffb
		g_object_set (G_OBJECT (cell), "cell-background-set", FALSE, NULL);
Packit fabffb
}
Packit fabffb
Packit fabffb
void
Packit fabffb
widget_set_error (GtkWidget *widget)
Packit fabffb
{
Packit fabffb
	g_return_if_fail (GTK_IS_WIDGET (widget));
Packit fabffb
Packit fabffb
	gtk_style_context_add_class (gtk_widget_get_style_context (widget), "error");
Packit fabffb
}
Packit fabffb
Packit fabffb
void
Packit fabffb
widget_unset_error (GtkWidget *widget)
Packit fabffb
{
Packit fabffb
	g_return_if_fail (GTK_IS_WIDGET (widget));
Packit fabffb
Packit fabffb
	gtk_style_context_remove_class (gtk_widget_get_style_context (widget), "error");
Packit fabffb
}
Packit fabffb
Packit fabffb
gboolean
Packit fabffb
utils_tree_model_get_int64 (GtkTreeModel *model,
Packit fabffb
                            GtkTreeIter *iter,
Packit fabffb
                            int column,
Packit fabffb
                            gint64 min_value,
Packit fabffb
                            gint64 max_value,
Packit fabffb
                            gboolean fail_if_missing,
Packit fabffb
                            gint64 *out,
Packit fabffb
                            char **out_raw)
Packit fabffb
{
Packit fabffb
	char *item = NULL;
Packit fabffb
	gboolean success = FALSE;
Packit fabffb
	gint64 val;
Packit fabffb
Packit fabffb
	g_return_val_if_fail (model, FALSE);
Packit fabffb
	g_return_val_if_fail (iter, FALSE);
Packit fabffb
Packit fabffb
	gtk_tree_model_get (model, iter, column, &item, -1);
Packit fabffb
	if (out_raw)
Packit fabffb
		*out_raw = item;
Packit fabffb
	if (!item || !strlen (item)) {
Packit fabffb
		if (!out_raw)
Packit fabffb
			g_free (item);
Packit fabffb
		return fail_if_missing ? FALSE : TRUE;
Packit fabffb
	}
Packit fabffb
Packit fabffb
	val = _nm_utils_ascii_str_to_int64 (item, 10, min_value, max_value, 0);
Packit fabffb
	if (errno)
Packit fabffb
		goto out;
Packit fabffb
Packit fabffb
	*out = val;
Packit fabffb
	success = TRUE;
Packit fabffb
out:
Packit fabffb
	if (!out_raw)
Packit fabffb
		g_free (item);
Packit fabffb
	return success;
Packit fabffb
}
Packit fabffb
Packit fabffb
gboolean
Packit fabffb
utils_tree_model_get_address (GtkTreeModel *model,
Packit fabffb
                              GtkTreeIter *iter,
Packit fabffb
                              int column,
Packit fabffb
                              int family,
Packit fabffb
                              gboolean fail_if_missing,
Packit fabffb
                              char **out,
Packit fabffb
                              char **out_raw)
Packit fabffb
{
Packit fabffb
	char *item = NULL;
Packit fabffb
	union {
Packit fabffb
		struct in_addr addr4;
Packit fabffb
		struct in6_addr addr6;
Packit fabffb
	} tmp_addr;
Packit fabffb
Packit fabffb
	g_return_val_if_fail (model, FALSE);
Packit fabffb
	g_return_val_if_fail (iter, FALSE);
Packit fabffb
	g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE);
Packit fabffb
Packit fabffb
	gtk_tree_model_get (model, iter, column, &item, -1);
Packit fabffb
	if (out_raw)
Packit fabffb
		*out_raw = item;
Packit fabffb
	if (!item || !strlen (item)) {
Packit fabffb
		if (!out_raw)
Packit fabffb
			g_free (item);
Packit fabffb
		return fail_if_missing ? FALSE : TRUE;
Packit fabffb
	}
Packit fabffb
Packit fabffb
	if (inet_pton (family, item, &tmp_addr) == 0)
Packit fabffb
		return FALSE;
Packit fabffb
Packit fabffb
	if (   (family == AF_INET && tmp_addr.addr4.s_addr == 0)
Packit fabffb
	    || (family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED (&tmp_addr.addr6))) {
Packit fabffb
		if (!out_raw)
Packit fabffb
			g_free (item);
Packit fabffb
		return fail_if_missing ? FALSE : TRUE;
Packit fabffb
	}
Packit fabffb
Packit fabffb
	*out = item;
Packit fabffb
	return TRUE;
Packit fabffb
}
Packit fabffb
Packit fabffb
gboolean
Packit fabffb
utils_tree_model_get_ip4_prefix (GtkTreeModel *model,
Packit fabffb
                                 GtkTreeIter *iter,
Packit fabffb
                                 int column,
Packit fabffb
                                 gboolean fail_if_missing,
Packit fabffb
                                 guint32 *out,
Packit fabffb
                                 char **out_raw)
Packit fabffb
{
Packit fabffb
	char *item = NULL;
Packit fabffb
	struct in_addr tmp_addr = { 0 };
Packit fabffb
	gboolean success = FALSE;
Packit fabffb
	glong tmp_prefix;
Packit fabffb
Packit fabffb
	g_return_val_if_fail (model, FALSE);
Packit fabffb
	g_return_val_if_fail (iter, FALSE);
Packit fabffb
Packit fabffb
	gtk_tree_model_get (model, iter, column, &item, -1);
Packit fabffb
	if (out_raw)
Packit fabffb
		*out_raw = item;
Packit fabffb
	if (!item || !strlen (item)) {
Packit fabffb
		if (!out_raw)
Packit fabffb
			g_free (item);
Packit fabffb
		return fail_if_missing ? FALSE : TRUE;
Packit fabffb
	}
Packit fabffb
Packit fabffb
	errno = 0;
Packit fabffb
Packit fabffb
	/* Is it a prefix? */
Packit fabffb
	if (!strchr (item, '.')) {
Packit fabffb
		tmp_prefix = strtol (item, NULL, 10);
Packit fabffb
		if (!errno && tmp_prefix >= 0 && tmp_prefix <= 32) {
Packit fabffb
			*out = tmp_prefix;
Packit fabffb
			success = TRUE;
Packit fabffb
			goto out;
Packit fabffb
		}
Packit fabffb
	}
Packit fabffb
Packit fabffb
	/* Is it a netmask? */
Packit fabffb
	if (inet_pton (AF_INET, item, &tmp_addr) > 0) {
Packit fabffb
		*out = nm_utils_ip4_netmask_to_prefix (tmp_addr.s_addr);
Packit fabffb
		success = TRUE;
Packit fabffb
	}
Packit fabffb
Packit fabffb
out:
Packit fabffb
	if (!out_raw)
Packit fabffb
		g_free (item);
Packit fabffb
	return success;
Packit fabffb
}
Packit fabffb
Packit fabffb
static gboolean
Packit fabffb
file_has_extension (const char *filename, const char *const*extensions)
Packit fabffb
{
Packit fabffb
	const char *p;
Packit fabffb
	gs_free char *ext = NULL;
Packit fabffb
Packit fabffb
	if (!filename)
Packit fabffb
		return FALSE;
Packit fabffb
Packit fabffb
	p = strrchr (filename, '.');
Packit fabffb
	if (!p)
Packit fabffb
		return FALSE;
Packit fabffb
Packit fabffb
	ext = g_ascii_strdown (p, -1);
Packit fabffb
	return g_strv_contains (extensions, ext);
Packit fabffb
}
Packit fabffb
Packit fabffb
static gboolean
Packit fabffb
cert_filter (const GtkFileFilterInfo *filter_info, gpointer data)
Packit fabffb
{
Packit fabffb
	static const char *const extensions[] = { ".der", ".pem", ".crt", ".cer", ".p12", NULL };
Packit fabffb
Packit fabffb
	return file_has_extension (filter_info->filename, extensions);
Packit fabffb
}
Packit fabffb
Packit fabffb
static gboolean
Packit fabffb
privkey_filter (const GtkFileFilterInfo *filter_info, gpointer user_data)
Packit fabffb
{
Packit fabffb
	static const char *const extensions[] = { ".der", ".pem", ".p12", ".key", NULL };
Packit fabffb
Packit fabffb
	return file_has_extension (filter_info->filename, extensions);
Packit fabffb
}
Packit fabffb
Packit fabffb
GtkFileFilter *
Packit fabffb
utils_cert_filter (void)
Packit fabffb
{
Packit fabffb
	GtkFileFilter *filter;
Packit fabffb
Packit fabffb
	filter = gtk_file_filter_new ();
Packit fabffb
	gtk_file_filter_add_custom (filter, GTK_FILE_FILTER_FILENAME, cert_filter, NULL, NULL);
Packit fabffb
	gtk_file_filter_set_name (filter, _("PEM certificates (*.pem, *.crt, *.cer)"));
Packit fabffb
Packit fabffb
	return filter;
Packit fabffb
}
Packit fabffb
Packit fabffb
GtkFileFilter *
Packit fabffb
utils_key_filter (void)
Packit fabffb
{
Packit fabffb
	GtkFileFilter *filter;
Packit fabffb
Packit fabffb
	filter = gtk_file_filter_new ();
Packit fabffb
	gtk_file_filter_add_custom (filter, GTK_FILE_FILTER_FILENAME, privkey_filter, NULL, NULL);
Packit fabffb
	gtk_file_filter_set_name (filter, _("DER, PEM, or PKCS#12 private keys (*.der, *.pem, *.p12, *.key)"));
Packit fabffb
Packit fabffb
	return filter;
Packit fabffb
}