Blame src/libnm-gtk/nm-mobile-providers.c

Packit fabffb
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
Packit fabffb
/*
Packit fabffb
 * This library is free software; you can redistribute it and/or
Packit fabffb
 * modify it under the terms of the GNU Lesser General Public
Packit fabffb
 * License as published by the Free Software Foundation; either
Packit fabffb
 * version 2 of the License, or (at your option) any later version.
Packit fabffb
 *
Packit fabffb
 * This library is distributed in the hope that it will be useful,
Packit fabffb
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit fabffb
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Packit fabffb
 * Lesser General Public License for more details.
Packit fabffb
 *
Packit fabffb
 * You should have received a copy of the GNU Lesser General Public
Packit fabffb
 * License along with this library; if not, write to the
Packit fabffb
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Packit fabffb
 * Boston, MA 02110-1301 USA.
Packit fabffb
 *
Packit fabffb
 * Copyright (C) 2009 Novell, Inc.
Packit fabffb
 * Author: Tambet Ingo (tambet@gmail.com).
Packit fabffb
 *
Packit fabffb
 * Copyright (C) 2009 - 2012 Red Hat, Inc.
Packit fabffb
 * Copyright (C) 2012 Lanedo GmbH
Packit fabffb
 */
Packit fabffb
Packit fabffb
#include "nm-default.h"
Packit fabffb
Packit fabffb
#include <string.h>
Packit fabffb
#include <errno.h>
Packit fabffb
#include <stdlib.h>
Packit fabffb
Packit fabffb
#include "nm-mobile-providers.h"
Packit fabffb
Packit fabffb
#define ISO_3166_COUNTRY_CODES ISO_CODES_PREFIX"/share/xml/iso-codes/iso_3166.xml"
Packit fabffb
#define ISO_CODES_LOCALESDIR ISO_CODES_PREFIX"/share/locale"
Packit fabffb
Packit fabffb
/******************************************************************************/
Packit fabffb
/* Access method type */
Packit fabffb
Packit fabffb
G_DEFINE_BOXED_TYPE (NMAMobileAccessMethod,
Packit fabffb
                     nma_mobile_access_method,
Packit fabffb
                     nma_mobile_access_method_ref,
Packit fabffb
                     nma_mobile_access_method_unref)
Packit fabffb
Packit fabffb
struct _NMAMobileAccessMethod {
Packit fabffb
	volatile gint refs;
Packit fabffb
Packit fabffb
	char *name;
Packit fabffb
	/* maps lang (char *) -> name (char *) */
Packit fabffb
	GHashTable *lcl_names;
Packit fabffb
Packit fabffb
	char *username;
Packit fabffb
	char *password;
Packit fabffb
	char *gateway;
Packit fabffb
	GPtrArray *dns; /* GPtrArray of 'char *' */
Packit fabffb
Packit fabffb
	/* Only used with 3GPP family type providers */
Packit fabffb
	char *apn;
Packit fabffb
Packit fabffb
	NMAMobileFamily family;
Packit fabffb
};
Packit fabffb
Packit fabffb
static NMAMobileAccessMethod *
Packit fabffb
access_method_new (void)
Packit fabffb
{
Packit fabffb
	NMAMobileAccessMethod *method;
Packit fabffb
Packit fabffb
	method = g_slice_new0 (NMAMobileAccessMethod);
Packit fabffb
	method->refs = 1;
Packit fabffb
	method->lcl_names = g_hash_table_new_full (g_str_hash, g_str_equal,
Packit fabffb
	                                           (GDestroyNotify) g_free,
Packit fabffb
	                                           (GDestroyNotify) g_free);
Packit fabffb
Packit fabffb
	return method;
Packit fabffb
}
Packit fabffb
Packit fabffb
NMAMobileAccessMethod *
Packit fabffb
nma_mobile_access_method_ref (NMAMobileAccessMethod *method)
Packit fabffb
{
Packit fabffb
	g_return_val_if_fail (method != NULL, NULL);
Packit fabffb
	g_return_val_if_fail (method->refs > 0, NULL);
Packit fabffb
Packit fabffb
	g_atomic_int_inc (&method->refs);
Packit fabffb
Packit fabffb
	return method;
Packit fabffb
}
Packit fabffb
Packit fabffb
void
Packit fabffb
nma_mobile_access_method_unref (NMAMobileAccessMethod *method)
Packit fabffb
{
Packit fabffb
	g_return_if_fail (method != NULL);
Packit fabffb
	g_return_if_fail (method->refs > 0);
Packit fabffb
Packit fabffb
	if (g_atomic_int_dec_and_test (&method->refs)) {
Packit fabffb
		g_free (method->name);
Packit fabffb
		g_hash_table_destroy (method->lcl_names);
Packit fabffb
		g_free (method->username);
Packit fabffb
		g_free (method->password);
Packit fabffb
		g_free (method->gateway);
Packit fabffb
		g_free (method->apn);
Packit fabffb
Packit fabffb
		if (method->dns)
Packit fabffb
			g_ptr_array_unref (method->dns);
Packit fabffb
Packit fabffb
		g_slice_free (NMAMobileAccessMethod, method);
Packit fabffb
	}
Packit fabffb
}
Packit fabffb
Packit fabffb
/**
Packit fabffb
 * nma_mobile_access_method_get_name:
Packit fabffb
 *
Packit fabffb
 * Returns: (transfer none): the name of the method.
Packit fabffb
 */
Packit fabffb
const gchar *
Packit fabffb
nma_mobile_access_method_get_name (NMAMobileAccessMethod *method)
Packit fabffb
{
Packit fabffb
	g_return_val_if_fail (method != NULL, NULL);
Packit fabffb
Packit fabffb
	return method->name;
Packit fabffb
}
Packit fabffb
Packit fabffb
/**
Packit fabffb
 * nma_mobile_access_method_get_username:
Packit fabffb
 *
Packit fabffb
 * Returns: (transfer none): the username.
Packit fabffb
 */
Packit fabffb
const gchar *
Packit fabffb
nma_mobile_access_method_get_username (NMAMobileAccessMethod *method)
Packit fabffb
{
Packit fabffb
	g_return_val_if_fail (method != NULL, NULL);
Packit fabffb
Packit fabffb
	return method->username;
Packit fabffb
}
Packit fabffb
Packit fabffb
/**
Packit fabffb
 * nma_mobile_access_method_get_password:
Packit fabffb
 *
Packit fabffb
 * Returns: (transfer none): the password.
Packit fabffb
 */
Packit fabffb
const gchar *
Packit fabffb
nma_mobile_access_method_get_password (NMAMobileAccessMethod *method)
Packit fabffb
{
Packit fabffb
	g_return_val_if_fail (method != NULL, NULL);
Packit fabffb
Packit fabffb
	return method->password;
Packit fabffb
}
Packit fabffb
Packit fabffb
/**
Packit fabffb
 * nma_mobile_access_method_get_gateway:
Packit fabffb
 *
Packit fabffb
 * Returns: (transfer none): the gateway.
Packit fabffb
 */
Packit fabffb
const gchar *
Packit fabffb
nma_mobile_access_method_get_gateway (NMAMobileAccessMethod *method)
Packit fabffb
{
Packit fabffb
	g_return_val_if_fail (method != NULL, NULL);
Packit fabffb
Packit fabffb
	return method->gateway;
Packit fabffb
}
Packit fabffb
Packit fabffb
/**
Packit fabffb
 * nma_mobile_access_method_get_dns:
Packit fabffb
 *
Packit fabffb
 * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): the list of DNS.
Packit fabffb
 */
Packit fabffb
const gchar **
Packit fabffb
nma_mobile_access_method_get_dns (NMAMobileAccessMethod *method)
Packit fabffb
{
Packit fabffb
	g_return_val_if_fail (method != NULL, NULL);
Packit fabffb
Packit fabffb
	return method->dns ? (const gchar **)method->dns->pdata : NULL;
Packit fabffb
}
Packit fabffb
Packit fabffb
/**
Packit fabffb
 * nma_mobile_access_method_get_3gpp_apn:
Packit fabffb
 *
Packit fabffb
 * Returns: (transfer none): the 3GPP APN.
Packit fabffb
 */
Packit fabffb
const gchar *
Packit fabffb
nma_mobile_access_method_get_3gpp_apn (NMAMobileAccessMethod *method)
Packit fabffb
{
Packit fabffb
	g_return_val_if_fail (method != NULL, NULL);
Packit fabffb
Packit fabffb
	return method->apn;
Packit fabffb
}
Packit fabffb
Packit fabffb
/**
Packit fabffb
 * nma_mobile_access_method_get_family:
Packit fabffb
 *
Packit fabffb
 * Returns: a #NMAMobileFamily.
Packit fabffb
 */
Packit fabffb
NMAMobileFamily
Packit fabffb
nma_mobile_access_method_get_family (NMAMobileAccessMethod *method)
Packit fabffb
{
Packit fabffb
	g_return_val_if_fail (method != NULL, NMA_MOBILE_FAMILY_UNKNOWN);
Packit fabffb
Packit fabffb
	return method->family;
Packit fabffb
}
Packit fabffb
Packit fabffb
/******************************************************************************/
Packit fabffb
/* Mobile provider type */
Packit fabffb
Packit fabffb
G_DEFINE_BOXED_TYPE (NMAMobileProvider,
Packit fabffb
                     nma_mobile_provider,
Packit fabffb
                     nma_mobile_provider_ref,
Packit fabffb
                     nma_mobile_provider_unref)
Packit fabffb
Packit fabffb
struct _NMAMobileProvider {
Packit fabffb
	volatile gint refs;
Packit fabffb
Packit fabffb
	char *name;
Packit fabffb
	/* maps lang (char *) -> name (char *) */
Packit fabffb
	GHashTable *lcl_names;
Packit fabffb
Packit fabffb
	GSList *methods; /* GSList of NmaMobileAccessMethod */
Packit fabffb
Packit fabffb
	GPtrArray *mcc_mnc;  /* GPtrArray of strings */
Packit fabffb
	GArray *cdma_sid; /* GArray of guint32 */
Packit fabffb
};
Packit fabffb
Packit fabffb
static NMAMobileProvider *
Packit fabffb
provider_new (void)
Packit fabffb
{
Packit fabffb
	NMAMobileProvider *provider;
Packit fabffb
Packit fabffb
	provider = g_slice_new0 (NMAMobileProvider);
Packit fabffb
	provider->refs = 1;
Packit fabffb
	provider->lcl_names = g_hash_table_new_full (g_str_hash, g_str_equal,
Packit fabffb
	                                             (GDestroyNotify) g_free,
Packit fabffb
	                                             (GDestroyNotify) g_free);
Packit fabffb
Packit fabffb
	return provider;
Packit fabffb
}
Packit fabffb
Packit fabffb
NMAMobileProvider *
Packit fabffb
nma_mobile_provider_ref (NMAMobileProvider *provider)
Packit fabffb
{
Packit fabffb
	g_return_val_if_fail (provider != NULL, NULL);
Packit fabffb
	g_return_val_if_fail (provider->refs > 0, NULL);
Packit fabffb
Packit fabffb
	g_atomic_int_inc (&provider->refs);
Packit fabffb
Packit fabffb
	return provider;
Packit fabffb
}
Packit fabffb
Packit fabffb
void
Packit fabffb
nma_mobile_provider_unref (NMAMobileProvider *provider)
Packit fabffb
{
Packit fabffb
	if (g_atomic_int_dec_and_test (&provider->refs)) {
Packit fabffb
		g_free (provider->name);
Packit fabffb
		g_hash_table_destroy (provider->lcl_names);
Packit fabffb
Packit fabffb
		g_slist_free_full (provider->methods, (GDestroyNotify) nma_mobile_access_method_unref);
Packit fabffb
Packit fabffb
		if (provider->mcc_mnc)
Packit fabffb
			g_ptr_array_unref (provider->mcc_mnc);
Packit fabffb
Packit fabffb
		if (provider->cdma_sid)
Packit fabffb
			g_array_unref (provider->cdma_sid);
Packit fabffb
Packit fabffb
		g_slice_free (NMAMobileProvider, provider);
Packit fabffb
	}
Packit fabffb
}
Packit fabffb
Packit fabffb
/**
Packit fabffb
 * nma_mobile_provider_get_name:
Packit fabffb
 *
Packit fabffb
 * Returns: (transfer none): the name of the provider.
Packit fabffb
 */
Packit fabffb
const gchar *
Packit fabffb
nma_mobile_provider_get_name (NMAMobileProvider *provider)
Packit fabffb
{
Packit fabffb
	g_return_val_if_fail (provider != NULL, NULL);
Packit fabffb
Packit fabffb
	return provider->name;
Packit fabffb
}
Packit fabffb
Packit fabffb
/**
Packit fabffb
 * nma_mobile_provider_get_methods:
Packit fabffb
 * @provider: a #NMAMobileProvider
Packit fabffb
 *
Packit fabffb
 * Returns: (element-type NMGtk.MobileAccessMethod) (transfer none): the
Packit fabffb
 *	 list of #NMAMobileAccessMethod this provider exposes.
Packit fabffb
 */
Packit fabffb
GSList *
Packit fabffb
nma_mobile_provider_get_methods (NMAMobileProvider *provider)
Packit fabffb
{
Packit fabffb
	g_return_val_if_fail (provider != NULL, NULL);
Packit fabffb
Packit fabffb
	return provider->methods;
Packit fabffb
}
Packit fabffb
Packit fabffb
/**
Packit fabffb
 * nma_mobile_provider_get_3gpp_mcc_mnc:
Packit fabffb
 * @provider: a #NMAMobileProvider
Packit fabffb
 *
Packit fabffb
 * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): a
Packit fabffb
 *	 list of strings with the MCC and MNC codes this provider exposes.
Packit fabffb
 */
Packit fabffb
const gchar **
Packit fabffb
nma_mobile_provider_get_3gpp_mcc_mnc (NMAMobileProvider *provider)
Packit fabffb
{
Packit fabffb
	g_return_val_if_fail (provider != NULL, NULL);
Packit fabffb
Packit fabffb
	return provider->mcc_mnc ? (const gchar **)provider->mcc_mnc->pdata : NULL;
Packit fabffb
}
Packit fabffb
Packit fabffb
/**
Packit fabffb
 * nma_mobile_provider_get_cdma_sid:
Packit fabffb
 * @provider: a #NMAMobileProvider
Packit fabffb
 *
Packit fabffb
 * Returns: (transfer none) (array zero-terminated=1) (element-type guint32): the
Packit fabffb
 *	 list of CDMA SIDs this provider exposes
Packit fabffb
 */
Packit fabffb
const guint32 *
Packit fabffb
nma_mobile_provider_get_cdma_sid (NMAMobileProvider *provider)
Packit fabffb
{
Packit fabffb
	g_return_val_if_fail (provider != NULL, NULL);
Packit fabffb
Packit fabffb
	return provider->cdma_sid ? (const guint32 *)provider->cdma_sid->data : NULL;
Packit fabffb
}
Packit fabffb
Packit fabffb
/******************************************************************************/
Packit fabffb
/* Country Info type */
Packit fabffb
Packit fabffb
G_DEFINE_BOXED_TYPE (NMACountryInfo,
Packit fabffb
                     nma_country_info,
Packit fabffb
                     nma_country_info_ref,
Packit fabffb
                     nma_country_info_unref)
Packit fabffb
Packit fabffb
struct _NMACountryInfo {
Packit fabffb
	volatile gint refs;
Packit fabffb
Packit fabffb
	char *country_code;
Packit fabffb
	char *country_name;
Packit fabffb
	GSList *providers;
Packit fabffb
};
Packit fabffb
Packit fabffb
static NMACountryInfo *
Packit fabffb
country_info_new (const char *country_code,
Packit fabffb
                  const gchar *country_name)
Packit fabffb
{
Packit fabffb
	NMACountryInfo *country_info;
Packit fabffb
Packit fabffb
	country_info = g_slice_new0 (NMACountryInfo);
Packit fabffb
	country_info->refs = 1;
Packit fabffb
	country_info->country_code = g_strdup (country_code);
Packit fabffb
	country_info->country_name = g_strdup (country_name);
Packit fabffb
	return country_info;
Packit fabffb
}
Packit fabffb
Packit fabffb
NMACountryInfo *
Packit fabffb
nma_country_info_ref (NMACountryInfo *country_info)
Packit fabffb
{
Packit fabffb
	g_return_val_if_fail (country_info != NULL, NULL);
Packit fabffb
	g_return_val_if_fail (country_info->refs > 0, NULL);
Packit fabffb
Packit fabffb
	g_atomic_int_inc (&country_info->refs);
Packit fabffb
Packit fabffb
	return country_info;
Packit fabffb
}
Packit fabffb
Packit fabffb
void
Packit fabffb
nma_country_info_unref (NMACountryInfo *country_info)
Packit fabffb
{
Packit fabffb
	if (g_atomic_int_dec_and_test (&country_info->refs)) {
Packit fabffb
		g_free (country_info->country_code);
Packit fabffb
		g_free (country_info->country_name);
Packit fabffb
		g_slist_free_full (country_info->providers,
Packit fabffb
		                   (GDestroyNotify) nma_mobile_provider_unref);
Packit fabffb
		g_slice_free (NMACountryInfo, country_info);
Packit fabffb
	}
Packit fabffb
}
Packit fabffb
Packit fabffb
/**
Packit fabffb
 * nma_country_info_get_country_code:
Packit fabffb
 *
Packit fabffb
 * Returns: (transfer none): the code of the country.
Packit fabffb
 */
Packit fabffb
const gchar *
Packit fabffb
nma_country_info_get_country_code (NMACountryInfo *country_info)
Packit fabffb
{
Packit fabffb
	g_return_val_if_fail (country_info != NULL, NULL);
Packit fabffb
Packit fabffb
	return country_info->country_code;
Packit fabffb
}
Packit fabffb
Packit fabffb
/**
Packit fabffb
 * nma_country_info_get_country_name:
Packit fabffb
 *
Packit fabffb
 * Returns: (transfer none): the name of the country.
Packit fabffb
 */
Packit fabffb
const gchar *
Packit fabffb
nma_country_info_get_country_name (NMACountryInfo *country_info)
Packit fabffb
{
Packit fabffb
	g_return_val_if_fail (country_info != NULL, NULL);
Packit fabffb
Packit fabffb
	return country_info->country_name;
Packit fabffb
}
Packit fabffb
Packit fabffb
/**
Packit fabffb
 * nma_country_info_get_providers:
Packit fabffb
 *
Packit fabffb
 * Returns: (element-type NMGtk.MobileProvider) (transfer none): the
Packit fabffb
 *	 list of #NMAMobileProvider this country exposes.
Packit fabffb
 */
Packit fabffb
GSList *
Packit fabffb
nma_country_info_get_providers (NMACountryInfo *country_info)
Packit fabffb
{
Packit fabffb
	g_return_val_if_fail (country_info != NULL, NULL);
Packit fabffb
Packit fabffb
	return country_info->providers;
Packit fabffb
}
Packit fabffb
Packit fabffb
/******************************************************************************/
Packit fabffb
/* XML Parser for iso_3166.xml */
Packit fabffb
Packit fabffb
static void
Packit fabffb
iso_3166_parser_start_element (GMarkupParseContext *context,
Packit fabffb
                               const gchar *element_name,
Packit fabffb
                               const gchar **attribute_names,
Packit fabffb
                               const gchar **attribute_values,
Packit fabffb
                               gpointer data,
Packit fabffb
                               GError **error)
Packit fabffb
{
Packit fabffb
	int i;
Packit fabffb
	const char *country_code = NULL;
Packit fabffb
	const char *common_name = NULL;
Packit fabffb
	const char *name = NULL;
Packit fabffb
	GHashTable *table = (GHashTable *) data;
Packit fabffb
Packit fabffb
	if (!strcmp (element_name, "iso_3166_entry")) {
Packit fabffb
		NMACountryInfo *country_info;
Packit fabffb
Packit fabffb
		for (i = 0; attribute_names && attribute_names[i]; i++) {
Packit fabffb
			if (!strcmp (attribute_names[i], "alpha_2_code"))
Packit fabffb
				country_code = attribute_values[i];
Packit fabffb
			else if (!strcmp (attribute_names[i], "common_name"))
Packit fabffb
				common_name = attribute_values[i];
Packit fabffb
			else if (!strcmp (attribute_names[i], "name"))
Packit fabffb
				name = attribute_values[i];
Packit fabffb
		}
Packit fabffb
		if (!country_code) {
Packit fabffb
			g_warning ("%s: missing mandatory 'alpha_2_code' atribute in '%s'"
Packit fabffb
			           " element.", __func__, element_name);
Packit fabffb
			return;
Packit fabffb
		}
Packit fabffb
		if (!name) {
Packit fabffb
			g_warning ("%s: missing mandatory 'name' atribute in '%s'"
Packit fabffb
			           " element.", __func__, element_name);
Packit fabffb
			return;
Packit fabffb
		}
Packit fabffb
Packit fabffb
		country_info = country_info_new (country_code,
Packit fabffb
		                                 dgettext ("iso_3166", common_name ? common_name : name));
Packit fabffb
Packit fabffb
		g_hash_table_insert (table, g_strdup (country_code), country_info);
Packit fabffb
	}
Packit fabffb
}
Packit fabffb
Packit fabffb
static const GMarkupParser iso_3166_parser = {
Packit fabffb
	iso_3166_parser_start_element,
Packit fabffb
	NULL, /* end element */
Packit fabffb
	NULL, /* text */
Packit fabffb
	NULL, /* passthrough */
Packit fabffb
	NULL  /* error */
Packit fabffb
};
Packit fabffb
Packit fabffb
static GHashTable *
Packit fabffb
read_country_codes (const gchar *country_codes_file,
Packit fabffb
                    GCancellable *cancellable,
Packit fabffb
                    GError **error)
Packit fabffb
{
Packit fabffb
	GHashTable *table = NULL;
Packit fabffb
	GMarkupParseContext *ctx;
Packit fabffb
	char *buf;
Packit fabffb
	gsize buf_len;
Packit fabffb
Packit fabffb
	/* Set domain to iso_3166 for country name translation */
Packit fabffb
	bindtextdomain ("iso_3166", ISO_CODES_LOCALESDIR);
Packit fabffb
	bind_textdomain_codeset ("iso_3166", "UTF-8");
Packit fabffb
Packit fabffb
	if (!g_file_get_contents (country_codes_file, &buf, &buf_len, error)) {
Packit fabffb
		g_prefix_error (error,
Packit fabffb
		                "Failed to load '%s' from 'iso-codes': ",
Packit fabffb
		                country_codes_file);
Packit fabffb
		return NULL;
Packit fabffb
	}
Packit fabffb
Packit fabffb
	table = g_hash_table_new_full (g_str_hash,
Packit fabffb
	                               g_str_equal,
Packit fabffb
	                               g_free,
Packit fabffb
	                               (GDestroyNotify)nma_country_info_unref);
Packit fabffb
Packit fabffb
	ctx = g_markup_parse_context_new (&iso_3166_parser, 0, table, NULL);
Packit fabffb
	if (!g_markup_parse_context_parse (ctx, buf, buf_len, error)) {
Packit fabffb
		g_prefix_error (error,
Packit fabffb
		                "Failed to parse '%s' from 'iso-codes': ",
Packit fabffb
		                country_codes_file);
Packit fabffb
		g_hash_table_destroy (table);
Packit fabffb
		return NULL;
Packit fabffb
	}
Packit fabffb
Packit fabffb
	g_markup_parse_context_free (ctx);
Packit fabffb
	g_free (buf);
Packit fabffb
	return table;
Packit fabffb
}
Packit fabffb
Packit fabffb
/******************************************************************************/
Packit fabffb
/* XML Parser for serviceproviders.xml */
Packit fabffb
Packit fabffb
typedef enum {
Packit fabffb
	PARSER_TOPLEVEL = 0,
Packit fabffb
	PARSER_COUNTRY,
Packit fabffb
	PARSER_PROVIDER,
Packit fabffb
	PARSER_METHOD_GSM,
Packit fabffb
	PARSER_METHOD_GSM_APN,
Packit fabffb
	PARSER_METHOD_CDMA,
Packit fabffb
	PARSER_ERROR
Packit fabffb
} MobileContextState;
Packit fabffb
Packit fabffb
typedef struct {
Packit fabffb
	GHashTable *table;
Packit fabffb
Packit fabffb
	char *current_country;
Packit fabffb
	GSList *current_providers;
Packit fabffb
	NMAMobileProvider *current_provider;
Packit fabffb
	NMAMobileAccessMethod *current_method;
Packit fabffb
Packit fabffb
	char *text_buffer;
Packit fabffb
	MobileContextState state;
Packit fabffb
} MobileParser;
Packit fabffb
Packit fabffb
static void
Packit fabffb
provider_list_free (gpointer data)
Packit fabffb
{
Packit fabffb
	GSList *list = (GSList *) data;
Packit fabffb
Packit fabffb
	while (list) {
Packit fabffb
		nma_mobile_provider_unref ((NMAMobileProvider *) list->data);
Packit fabffb
		list = g_slist_delete_link (list, list);
Packit fabffb
	}
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
parser_toplevel_start (MobileParser *parser,
Packit fabffb
                       const char *name,
Packit fabffb
                       const char **attribute_names,
Packit fabffb
                       const char **attribute_values)
Packit fabffb
{
Packit fabffb
	int i;
Packit fabffb
Packit fabffb
	if (!strcmp (name, "serviceproviders")) {
Packit fabffb
		for (i = 0; attribute_names && attribute_names[i]; i++) {
Packit fabffb
			if (!strcmp (attribute_names[i], "format")) {
Packit fabffb
				if (strcmp (attribute_values[i], "2.0")) {
Packit fabffb
					g_warning ("%s: mobile broadband provider database format '%s'"
Packit fabffb
					           " not supported.", __func__, attribute_values[i]);
Packit fabffb
					parser->state = PARSER_ERROR;
Packit fabffb
					break;
Packit fabffb
				}
Packit fabffb
			}
Packit fabffb
		}
Packit fabffb
	} else if (!strcmp (name, "country")) {
Packit fabffb
		for (i = 0; attribute_names && attribute_names[i]; i++) {
Packit fabffb
			if (!strcmp (attribute_names[i], "code")) {
Packit fabffb
				char *country_code;
Packit fabffb
				NMACountryInfo *country_info;
Packit fabffb
Packit fabffb
				country_code = g_ascii_strup (attribute_values[i], -1);
Packit fabffb
				country_info = g_hash_table_lookup (parser->table, country_code);
Packit fabffb
				/* Ensure we have a country provider for this country code */
Packit fabffb
				if (!country_info) {
Packit fabffb
					g_warning ("%s: adding providers for unknown country '%s'", __func__, country_code);
Packit fabffb
					country_info = country_info_new (country_code, NULL);
Packit fabffb
					g_hash_table_insert (parser->table, country_code, country_info);
Packit fabffb
				}
Packit fabffb
				parser->current_country = country_code;
Packit fabffb
Packit fabffb
				parser->state = PARSER_COUNTRY;
Packit fabffb
				break;
Packit fabffb
			}
Packit fabffb
		}
Packit fabffb
	}
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
parser_country_start (MobileParser *parser,
Packit fabffb
                      const char *name,
Packit fabffb
                      const char **attribute_names,
Packit fabffb
                      const char **attribute_values)
Packit fabffb
{
Packit fabffb
	if (!strcmp (name, "provider")) {
Packit fabffb
		parser->state = PARSER_PROVIDER;
Packit fabffb
		parser->current_provider = provider_new ();
Packit fabffb
	}
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
parser_provider_start (MobileParser *parser,
Packit fabffb
                       const char *name,
Packit fabffb
                       const char **attribute_names,
Packit fabffb
                       const char **attribute_values)
Packit fabffb
{
Packit fabffb
	if (!strcmp (name, "gsm"))
Packit fabffb
		parser->state = PARSER_METHOD_GSM;
Packit fabffb
	else if (!strcmp (name, "cdma")) {
Packit fabffb
		parser->state = PARSER_METHOD_CDMA;
Packit fabffb
		parser->current_method = access_method_new ();
Packit fabffb
	}
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
parser_gsm_start (MobileParser *parser,
Packit fabffb
                  const char *name,
Packit fabffb
                  const char **attribute_names,
Packit fabffb
                  const char **attribute_values)
Packit fabffb
{
Packit fabffb
	if (!strcmp (name, "network-id")) {
Packit fabffb
		const char *mcc = NULL, *mnc = NULL;
Packit fabffb
		int i;
Packit fabffb
Packit fabffb
		for (i = 0; attribute_names && attribute_names[i]; i++) {
Packit fabffb
			if (!strcmp (attribute_names[i], "mcc"))
Packit fabffb
				mcc = attribute_values[i];
Packit fabffb
			else if (!strcmp (attribute_names[i], "mnc"))
Packit fabffb
				mnc = attribute_values[i];
Packit fabffb
Packit fabffb
			if (mcc && strlen (mcc) && mnc && strlen (mnc)) {
Packit fabffb
				gchar *mccmnc;
Packit fabffb
Packit fabffb
				if (!parser->current_provider->mcc_mnc)
Packit fabffb
					parser->current_provider->mcc_mnc = g_ptr_array_new_full (2, g_free);
Packit fabffb
Packit fabffb
				mccmnc = g_strdup_printf ("%s%s", mcc, mnc);
Packit fabffb
				g_ptr_array_add (parser->current_provider->mcc_mnc, mccmnc);
Packit fabffb
				break;
Packit fabffb
			}
Packit fabffb
		}
Packit fabffb
	} else if (!strcmp (name, "apn")) {
Packit fabffb
		int i;
Packit fabffb
Packit fabffb
		for (i = 0; attribute_names && attribute_names[i]; i++) {
Packit fabffb
			if (!strcmp (attribute_names[i], "value")) {
Packit fabffb
Packit fabffb
				parser->state = PARSER_METHOD_GSM_APN;
Packit fabffb
				parser->current_method = access_method_new ();
Packit fabffb
				parser->current_method->apn = g_strstrip (g_strdup (attribute_values[i]));
Packit fabffb
				break;
Packit fabffb
			}
Packit fabffb
		}
Packit fabffb
	}
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
parser_cdma_start (MobileParser *parser,
Packit fabffb
                   const char *name,
Packit fabffb
                   const char **attribute_names,
Packit fabffb
                   const char **attribute_values)
Packit fabffb
{
Packit fabffb
	if (!strcmp (name, "sid")) {
Packit fabffb
		int i;
Packit fabffb
Packit fabffb
		for (i = 0; attribute_names && attribute_names[i]; i++) {
Packit fabffb
			if (!strcmp (attribute_names[i], "value")) {
Packit fabffb
				guint32 tmp;
Packit fabffb
Packit fabffb
				errno = 0;
Packit fabffb
				tmp = (guint32) strtoul (attribute_values[i], NULL, 10);
Packit fabffb
				if (errno == 0 && tmp > 0) {
Packit fabffb
					if (!parser->current_provider->cdma_sid)
Packit fabffb
						parser->current_provider->cdma_sid = g_array_sized_new (TRUE, FALSE, sizeof (guint32), 2);
Packit fabffb
					g_array_append_val (parser->current_provider->cdma_sid, tmp);
Packit fabffb
				}
Packit fabffb
				break;
Packit fabffb
			}
Packit fabffb
		}
Packit fabffb
	}
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
mobile_parser_start_element (GMarkupParseContext *context,
Packit fabffb
                             const gchar *element_name,
Packit fabffb
                             const gchar **attribute_names,
Packit fabffb
                             const gchar **attribute_values,
Packit fabffb
                             gpointer data,
Packit fabffb
                             GError **error)
Packit fabffb
{
Packit fabffb
	MobileParser *parser = (MobileParser *) data;
Packit fabffb
Packit fabffb
	if (parser->text_buffer) {
Packit fabffb
		g_free (parser->text_buffer);
Packit fabffb
		parser->text_buffer = NULL;
Packit fabffb
	}
Packit fabffb
Packit fabffb
	switch (parser->state) {
Packit fabffb
	case PARSER_TOPLEVEL:
Packit fabffb
		parser_toplevel_start (parser, element_name, attribute_names, attribute_values);
Packit fabffb
		break;
Packit fabffb
	case PARSER_COUNTRY:
Packit fabffb
		parser_country_start (parser, element_name, attribute_names, attribute_values);
Packit fabffb
		break;
Packit fabffb
	case PARSER_PROVIDER:
Packit fabffb
		parser_provider_start (parser, element_name, attribute_names, attribute_values);
Packit fabffb
		break;
Packit fabffb
	case PARSER_METHOD_GSM:
Packit fabffb
		parser_gsm_start (parser, element_name, attribute_names, attribute_values);
Packit fabffb
		break;
Packit fabffb
	case PARSER_METHOD_CDMA:
Packit fabffb
		parser_cdma_start (parser, element_name, attribute_names, attribute_values);
Packit fabffb
		break;
Packit fabffb
	default:
Packit fabffb
		break;
Packit fabffb
	}
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
parser_country_end (MobileParser *parser,
Packit fabffb
                    const char *name)
Packit fabffb
{
Packit fabffb
	if (!strcmp (name, "country")) {
Packit fabffb
		NMACountryInfo *country_info;
Packit fabffb
Packit fabffb
		country_info = g_hash_table_lookup (parser->table, parser->current_country);
Packit fabffb
		g_assert (country_info);
Packit fabffb
Packit fabffb
		/* Store providers for this country */
Packit fabffb
		country_info->providers = parser->current_providers;
Packit fabffb
Packit fabffb
		g_free (parser->current_country);
Packit fabffb
		parser->current_country = NULL;
Packit fabffb
		parser->current_providers = NULL;
Packit fabffb
		g_free (parser->text_buffer);
Packit fabffb
		parser->text_buffer = NULL;
Packit fabffb
		parser->state = PARSER_TOPLEVEL;
Packit fabffb
	}
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
parser_provider_end (MobileParser *parser,
Packit fabffb
                     const char *name)
Packit fabffb
{
Packit fabffb
	if (!strcmp (name, "name")) {
Packit fabffb
		if (!parser->current_provider->name) {
Packit fabffb
			/* Use the first one. */
Packit fabffb
			parser->current_provider->name = parser->text_buffer;
Packit fabffb
			parser->text_buffer = NULL;
Packit fabffb
		}
Packit fabffb
	} else if (!strcmp (name, "provider")) {
Packit fabffb
		if (parser->current_provider->mcc_mnc)
Packit fabffb
			g_ptr_array_add (parser->current_provider->mcc_mnc, NULL);
Packit fabffb
Packit fabffb
		parser->current_provider->methods = g_slist_reverse (parser->current_provider->methods);
Packit fabffb
Packit fabffb
		parser->current_providers = g_slist_prepend (parser->current_providers, parser->current_provider);
Packit fabffb
		parser->current_provider = NULL;
Packit fabffb
		g_free (parser->text_buffer);
Packit fabffb
		parser->text_buffer = NULL;
Packit fabffb
		parser->state = PARSER_COUNTRY;
Packit fabffb
	}
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
parser_gsm_end (MobileParser *parser,
Packit fabffb
                const char *name)
Packit fabffb
{
Packit fabffb
	if (!strcmp (name, "gsm")) {
Packit fabffb
		g_free (parser->text_buffer);
Packit fabffb
		parser->text_buffer = NULL;
Packit fabffb
		parser->state = PARSER_PROVIDER;
Packit fabffb
	}
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
parser_gsm_apn_end (MobileParser *parser,
Packit fabffb
                    const char *name)
Packit fabffb
{
Packit fabffb
	if (!strcmp (name, "name")) {
Packit fabffb
		if (!parser->current_method->name) {
Packit fabffb
			/* Use the first one. */
Packit fabffb
			parser->current_method->name = parser->text_buffer;
Packit fabffb
			parser->text_buffer = NULL;
Packit fabffb
		}
Packit fabffb
	} else if (!strcmp (name, "username")) {
Packit fabffb
		parser->current_method->username = parser->text_buffer;
Packit fabffb
		parser->text_buffer = NULL;
Packit fabffb
	} else if (!strcmp (name, "password")) {
Packit fabffb
		parser->current_method->password = parser->text_buffer;
Packit fabffb
		parser->text_buffer = NULL;
Packit fabffb
	} else if (!strcmp (name, "dns")) {
Packit fabffb
		if (!parser->current_method->dns)
Packit fabffb
			parser->current_method->dns = g_ptr_array_new_full (2, g_free);
Packit fabffb
		g_ptr_array_add (parser->current_method->dns, parser->text_buffer);
Packit fabffb
		parser->text_buffer = NULL;
Packit fabffb
	} else if (!strcmp (name, "gateway")) {
Packit fabffb
		parser->current_method->gateway = parser->text_buffer;
Packit fabffb
		parser->text_buffer = NULL;
Packit fabffb
	} else if (!strcmp (name, "apn")) {
Packit fabffb
		parser->current_method->family = NMA_MOBILE_FAMILY_3GPP;
Packit fabffb
Packit fabffb
		if (!parser->current_method->name)
Packit fabffb
			parser->current_method->name = g_strdup (_("Default"));
Packit fabffb
Packit fabffb
		if (parser->current_method->dns)
Packit fabffb
			g_ptr_array_add (parser->current_method->dns, NULL);
Packit fabffb
Packit fabffb
		parser->current_provider->methods = g_slist_prepend (parser->current_provider->methods,
Packit fabffb
		                                                     parser->current_method);
Packit fabffb
		parser->current_method = NULL;
Packit fabffb
		g_free (parser->text_buffer);
Packit fabffb
		parser->text_buffer = NULL;
Packit fabffb
		parser->state = PARSER_METHOD_GSM;
Packit fabffb
	}
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
parser_cdma_end (MobileParser *parser,
Packit fabffb
                 const char *name)
Packit fabffb
{
Packit fabffb
	if (!strcmp (name, "username")) {
Packit fabffb
		parser->current_method->username = parser->text_buffer;
Packit fabffb
		parser->text_buffer = NULL;
Packit fabffb
	} else if (!strcmp (name, "password")) {
Packit fabffb
		parser->current_method->password = parser->text_buffer;
Packit fabffb
		parser->text_buffer = NULL;
Packit fabffb
	} else if (!strcmp (name, "dns")) {
Packit fabffb
		if (!parser->current_method->dns)
Packit fabffb
			parser->current_method->dns = g_ptr_array_new_full (2, g_free);
Packit fabffb
		g_ptr_array_add (parser->current_method->dns, parser->text_buffer);
Packit fabffb
		parser->text_buffer = NULL;
Packit fabffb
	} else if (!strcmp (name, "gateway")) {
Packit fabffb
		parser->current_method->gateway = parser->text_buffer;
Packit fabffb
		parser->text_buffer = NULL;
Packit fabffb
	} else if (!strcmp (name, "cdma")) {
Packit fabffb
		parser->current_method->family = NMA_MOBILE_FAMILY_CDMA;
Packit fabffb
Packit fabffb
		if (!parser->current_method->name)
Packit fabffb
			parser->current_method->name = g_strdup (parser->current_provider->name);
Packit fabffb
Packit fabffb
		if (parser->current_method->dns)
Packit fabffb
			g_ptr_array_add (parser->current_method->dns, NULL);
Packit fabffb
Packit fabffb
		parser->current_provider->methods = g_slist_prepend (parser->current_provider->methods,
Packit fabffb
		                                                     parser->current_method);
Packit fabffb
		parser->current_method = NULL;
Packit fabffb
		g_free (parser->text_buffer);
Packit fabffb
		parser->text_buffer = NULL;
Packit fabffb
		parser->state = PARSER_PROVIDER;
Packit fabffb
	}
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
mobile_parser_end_element (GMarkupParseContext *context,
Packit fabffb
                           const gchar *element_name,
Packit fabffb
                           gpointer data,
Packit fabffb
                           GError **error)
Packit fabffb
{
Packit fabffb
	MobileParser *parser = (MobileParser *) data;
Packit fabffb
Packit fabffb
	switch (parser->state) {
Packit fabffb
	case PARSER_COUNTRY:
Packit fabffb
		parser_country_end (parser, element_name);
Packit fabffb
		break;
Packit fabffb
	case PARSER_PROVIDER:
Packit fabffb
		parser_provider_end (parser, element_name);
Packit fabffb
		break;
Packit fabffb
	case PARSER_METHOD_GSM:
Packit fabffb
		parser_gsm_end (parser, element_name);
Packit fabffb
		break;
Packit fabffb
	case PARSER_METHOD_GSM_APN:
Packit fabffb
		parser_gsm_apn_end (parser, element_name);
Packit fabffb
		break;
Packit fabffb
	case PARSER_METHOD_CDMA:
Packit fabffb
		parser_cdma_end (parser, element_name);
Packit fabffb
		break;
Packit fabffb
	default:
Packit fabffb
		break;
Packit fabffb
	}
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
mobile_parser_characters (GMarkupParseContext *context,
Packit fabffb
                          const gchar *text,
Packit fabffb
                          gsize text_len,
Packit fabffb
                          gpointer data,
Packit fabffb
                          GError **error)
Packit fabffb
{
Packit fabffb
	MobileParser *parser = (MobileParser *) data;
Packit fabffb
Packit fabffb
	g_free (parser->text_buffer);
Packit fabffb
	parser->text_buffer = g_strdup (text);
Packit fabffb
}
Packit fabffb
Packit fabffb
static const GMarkupParser mobile_parser = {
Packit fabffb
	mobile_parser_start_element,
Packit fabffb
	mobile_parser_end_element,
Packit fabffb
	mobile_parser_characters,
Packit fabffb
	NULL, /* passthrough */
Packit fabffb
	NULL /* error */
Packit fabffb
};
Packit fabffb
Packit fabffb
static gboolean
Packit fabffb
read_service_providers (GHashTable *countries,
Packit fabffb
                        const gchar *service_providers,
Packit fabffb
                        GCancellable *cancellable,
Packit fabffb
                        GError **error)
Packit fabffb
{
Packit fabffb
	GMarkupParseContext *ctx;
Packit fabffb
	GIOChannel *channel;
Packit fabffb
	MobileParser parser;
Packit fabffb
	char buffer[4096];
Packit fabffb
	GIOStatus status;
Packit fabffb
	gsize len = 0;
Packit fabffb
Packit fabffb
	memset (&parser, 0, sizeof (MobileParser));
Packit fabffb
    parser.table = countries;
Packit fabffb
Packit fabffb
	channel = g_io_channel_new_file (service_providers, "r", error);
Packit fabffb
	if (!channel) {
Packit fabffb
		g_prefix_error (error,
Packit fabffb
		                "Could not read '%s': ",
Packit fabffb
		                service_providers);
Packit fabffb
		return FALSE;
Packit fabffb
	}
Packit fabffb
Packit fabffb
	parser.state = PARSER_TOPLEVEL;
Packit fabffb
Packit fabffb
	ctx = g_markup_parse_context_new (&mobile_parser, 0, &parser, NULL);
Packit fabffb
Packit fabffb
	status = G_IO_STATUS_NORMAL;
Packit fabffb
	while (status == G_IO_STATUS_NORMAL) {
Packit fabffb
		status = g_io_channel_read_chars (channel, buffer, sizeof (buffer), &len, error);
Packit fabffb
Packit fabffb
		switch (status) {
Packit fabffb
		case G_IO_STATUS_NORMAL:
Packit fabffb
			if (!g_markup_parse_context_parse (ctx, buffer, len, error)) {
Packit fabffb
				status = G_IO_STATUS_ERROR;
Packit fabffb
				g_prefix_error (error,
Packit fabffb
				                "Error while parsing XML at '%s': ",
Packit fabffb
				                service_providers);
Packit fabffb
			}
Packit fabffb
			break;
Packit fabffb
		case G_IO_STATUS_EOF:
Packit fabffb
			break;
Packit fabffb
		case G_IO_STATUS_ERROR:
Packit fabffb
			g_prefix_error (error,
Packit fabffb
			                "Error while reading '%s': ",
Packit fabffb
			                service_providers);
Packit fabffb
			break;
Packit fabffb
		case G_IO_STATUS_AGAIN:
Packit fabffb
			/* FIXME: Try again a few times, but really, it never happens, right? */
Packit fabffb
			break;
Packit fabffb
		}
Packit fabffb
Packit fabffb
		if (g_cancellable_set_error_if_cancelled (cancellable, error))
Packit fabffb
			status = G_IO_STATUS_ERROR;
Packit fabffb
	}
Packit fabffb
Packit fabffb
	g_io_channel_unref (channel);
Packit fabffb
	g_markup_parse_context_free (ctx);
Packit fabffb
Packit fabffb
	if (parser.current_provider) {
Packit fabffb
		g_warning ("pending current provider");
Packit fabffb
		nma_mobile_provider_unref (parser.current_provider);
Packit fabffb
	}
Packit fabffb
Packit fabffb
	if (parser.current_providers) {
Packit fabffb
		g_warning ("pending current providers");
Packit fabffb
		provider_list_free (parser.current_providers);
Packit fabffb
	}
Packit fabffb
Packit fabffb
	g_free (parser.current_country);
Packit fabffb
	g_free (parser.text_buffer);
Packit fabffb
Packit fabffb
	return (status == G_IO_STATUS_EOF);
Packit fabffb
}
Packit fabffb
Packit fabffb
static GHashTable *
Packit fabffb
mobile_providers_parse_sync (const gchar *country_codes,
Packit fabffb
                             const gchar *service_providers,
Packit fabffb
                             GCancellable *cancellable,
Packit fabffb
                             GError **error)
Packit fabffb
{
Packit fabffb
	GHashTable *countries;
Packit fabffb
Packit fabffb
	/* Use default paths if none given */
Packit fabffb
	if (!country_codes)
Packit fabffb
		country_codes = ISO_3166_COUNTRY_CODES;
Packit fabffb
	if (!service_providers)
Packit fabffb
		service_providers = MOBILE_BROADBAND_PROVIDER_INFO_DATABASE;
Packit fabffb
Packit fabffb
	countries = read_country_codes (country_codes,
Packit fabffb
	                                cancellable,
Packit fabffb
	                                error);
Packit fabffb
	if (!countries)
Packit fabffb
		return NULL;
Packit fabffb
Packit fabffb
	if (!read_service_providers (countries,
Packit fabffb
	                             service_providers,
Packit fabffb
	                             cancellable,
Packit fabffb
	                             error)) {
Packit fabffb
		g_hash_table_unref (countries);
Packit fabffb
		return NULL;
Packit fabffb
	}
Packit fabffb
Packit fabffb
	return countries;
Packit fabffb
}
Packit fabffb
Packit fabffb
/******************************************************************************/
Packit fabffb
/* Dump to stdout contents */
Packit fabffb
Packit fabffb
static void
Packit fabffb
dump_generic (NMAMobileAccessMethod *method)
Packit fabffb
{
Packit fabffb
	g_print ("		  username: %s\n", method->username ? method->username : "");
Packit fabffb
	g_print ("		  password: %s\n", method->password ? method->password : "");
Packit fabffb
Packit fabffb
	if (method->dns) {
Packit fabffb
		guint i;
Packit fabffb
		const gchar **dns;
Packit fabffb
		GString *dns_str;
Packit fabffb
Packit fabffb
		dns = nma_mobile_access_method_get_dns (method);
Packit fabffb
		dns_str = g_string_new (NULL);
Packit fabffb
		for (i = 0; dns[i]; i++)
Packit fabffb
			g_string_append_printf (dns_str, "%s%s", i == 0 ? "" : ", ", dns[i]);
Packit fabffb
		g_print ("		  dns	  : %s\n", dns_str->str);
Packit fabffb
		g_string_free (dns_str, TRUE);
Packit fabffb
	}
Packit fabffb
Packit fabffb
	g_print ("		  gateway : %s\n", method->gateway ? method->gateway : "");
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
dump_cdma (NMAMobileAccessMethod *method)
Packit fabffb
{
Packit fabffb
	g_print ("	   CDMA: %s\n", method->name);
Packit fabffb
Packit fabffb
	dump_generic (method);
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
dump_3gpp (NMAMobileAccessMethod *method)
Packit fabffb
{
Packit fabffb
	g_print ("	   APN: %s (%s)\n", method->name, method->apn);
Packit fabffb
Packit fabffb
	dump_generic (method);
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
dump_country (gpointer key, gpointer value, gpointer user_data)
Packit fabffb
{
Packit fabffb
	GSList *miter, *citer;
Packit fabffb
	NMACountryInfo *country_info = value;
Packit fabffb
Packit fabffb
	g_print ("Country: %s (%s)\n",
Packit fabffb
	         country_info->country_code,
Packit fabffb
	         country_info->country_name);
Packit fabffb
Packit fabffb
	for (citer = country_info->providers; citer; citer = g_slist_next (citer)) {
Packit fabffb
		NMAMobileProvider *provider = citer->data;
Packit fabffb
		const gchar **mcc_mnc;
Packit fabffb
		const guint *sid;
Packit fabffb
		guint n;
Packit fabffb
Packit fabffb
		g_print ("	  Provider: %s (%s)\n", provider->name, (const char *) key);
Packit fabffb
Packit fabffb
		mcc_mnc = nma_mobile_provider_get_3gpp_mcc_mnc (provider);
Packit fabffb
		if (mcc_mnc) {
Packit fabffb
			for (n = 0; mcc_mnc[n]; n++)
Packit fabffb
				g_print ("		  MCC/MNC: %s\n", mcc_mnc[n]);
Packit fabffb
		}
Packit fabffb
Packit fabffb
		sid = nma_mobile_provider_get_cdma_sid (provider);
Packit fabffb
		if (sid) {
Packit fabffb
			for (n = 0; sid[n]; n++)
Packit fabffb
				g_print ("		  SID: %u\n", sid[n]);
Packit fabffb
		}
Packit fabffb
Packit fabffb
		for (miter = provider->methods; miter; miter = g_slist_next (miter)) {
Packit fabffb
			NMAMobileAccessMethod *method = miter->data;
Packit fabffb
Packit fabffb
			switch (method->family) {
Packit fabffb
			case NMA_MOBILE_FAMILY_CDMA:
Packit fabffb
				dump_cdma (method);
Packit fabffb
				break;
Packit fabffb
			case NMA_MOBILE_FAMILY_3GPP:
Packit fabffb
				dump_3gpp (method);
Packit fabffb
				break;
Packit fabffb
			default:
Packit fabffb
				break;
Packit fabffb
			}
Packit fabffb
			g_print ("\n");
Packit fabffb
		}
Packit fabffb
	}
Packit fabffb
}
Packit fabffb
Packit fabffb
/******************************************************************************/
Packit fabffb
/* Mobile providers database type */
Packit fabffb
Packit fabffb
static void initable_iface_init       (GInitableIface      *iface);
Packit fabffb
static void async_initable_iface_init (GAsyncInitableIface *iface);
Packit fabffb
Packit fabffb
G_DEFINE_TYPE_EXTENDED (NMAMobileProvidersDatabase, nma_mobile_providers_database, G_TYPE_OBJECT, 0,
Packit fabffb
                        G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)
Packit fabffb
                        G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init))
Packit fabffb
Packit fabffb
enum {
Packit fabffb
	PROP_0,
Packit fabffb
	PROP_COUNTRY_CODES_PATH,
Packit fabffb
	PROP_SERVICE_PROVIDERS_PATH,
Packit fabffb
	PROP_LAST
Packit fabffb
};
Packit fabffb
Packit fabffb
static GParamSpec *properties[PROP_LAST];
Packit fabffb
Packit fabffb
struct _NMAMobileProvidersDatabasePrivate {
Packit fabffb
	/* Paths to input files */
Packit fabffb
	gchar *country_codes_path;
Packit fabffb
	gchar *service_providers_path;
Packit fabffb
Packit fabffb
	/* The HT with country code as key and NMACountryInfo as value. */
Packit fabffb
	GHashTable *countries;
Packit fabffb
};
Packit fabffb
Packit fabffb
/**********************************/
Packit fabffb
Packit fabffb
/**
Packit fabffb
 * nma_mobile_providers_database_get_countries:
Packit fabffb
 * @self: a #NMAMobileProvidersDatabase.
Packit fabffb
 *
Packit fabffb
 * Returns: (element-type utf8 NMGtk.CountryInfo) (transfer none): a
Packit fabffb
 *	 hash table where keys are country names #gchar and values are #NMACountryInfo.
Packit fabffb
 */
Packit fabffb
GHashTable *
Packit fabffb
nma_mobile_providers_database_get_countries (NMAMobileProvidersDatabase *self)
Packit fabffb
{
Packit fabffb
	g_return_val_if_fail (NMA_IS_MOBILE_PROVIDERS_DATABASE (self), NULL);
Packit fabffb
Packit fabffb
	/* Warn if the object hasn't been initialized */
Packit fabffb
	g_return_val_if_fail (self->priv->countries != NULL, NULL);
Packit fabffb
Packit fabffb
	return self->priv->countries;
Packit fabffb
}
Packit fabffb
Packit fabffb
/**
Packit fabffb
 * nma_mobile_providers_database_dump:
Packit fabffb
 * @self: a #NMAMobileProvidersDatabase.
Packit fabffb
 *
Packit fabffb
 */
Packit fabffb
void
Packit fabffb
nma_mobile_providers_database_dump (NMAMobileProvidersDatabase *self)
Packit fabffb
{
Packit fabffb
	g_return_if_fail (NMA_IS_MOBILE_PROVIDERS_DATABASE (self));
Packit fabffb
Packit fabffb
	/* Warn if the object hasn't been initialized */
Packit fabffb
	g_return_if_fail (self->priv->countries != NULL);
Packit fabffb
Packit fabffb
	g_hash_table_foreach (self->priv->countries, dump_country, NULL);
Packit fabffb
}
Packit fabffb
Packit fabffb
/**
Packit fabffb
 * nma_mobile_providers_database_lookup_country:
Packit fabffb
 * @self: a #NMAMobileProvidersDatabase.
Packit fabffb
 * @country_code: the country code string to look for.
Packit fabffb
 *
Packit fabffb
 * Returns: (transfer none): a #NMACountryInfo or %NULL if not found.
Packit fabffb
 */
Packit fabffb
NMACountryInfo *
Packit fabffb
nma_mobile_providers_database_lookup_country (NMAMobileProvidersDatabase *self,
Packit fabffb
                                              const gchar *country_code)
Packit fabffb
{
Packit fabffb
	g_return_val_if_fail (NMA_IS_MOBILE_PROVIDERS_DATABASE (self), NULL);
Packit fabffb
Packit fabffb
	/* Warn if the object hasn't been initialized */
Packit fabffb
	g_return_val_if_fail (self->priv->countries != NULL, NULL);
Packit fabffb
Packit fabffb
	return (NMACountryInfo *) g_hash_table_lookup (self->priv->countries, country_code);
Packit fabffb
}
Packit fabffb
Packit fabffb
/**
Packit fabffb
 * nma_mobile_providers_database_lookup_3gpp_mcc_mnc:
Packit fabffb
 * @self: a #NMAMobileProvidersDatabase.
Packit fabffb
 * @mccmnc: the MCC/MNC string to look for.
Packit fabffb
 *
Packit fabffb
 * Returns: (transfer none): a #NMAMobileProvider or %NULL if not found.
Packit fabffb
 */
Packit fabffb
NMAMobileProvider *
Packit fabffb
nma_mobile_providers_database_lookup_3gpp_mcc_mnc (NMAMobileProvidersDatabase *self,
Packit fabffb
                                                   const gchar *mccmnc)
Packit fabffb
{
Packit fabffb
	GHashTableIter iter;
Packit fabffb
	gpointer value;
Packit fabffb
	GSList *piter;
Packit fabffb
	NMAMobileProvider *provider_match_2mnc = NULL;
Packit fabffb
	guint mccmnc_len;
Packit fabffb
Packit fabffb
	g_return_val_if_fail (NMA_IS_MOBILE_PROVIDERS_DATABASE (self), NULL);
Packit fabffb
	g_return_val_if_fail (mccmnc != NULL, NULL);
Packit fabffb
	/* Warn if the object hasn't been initialized */
Packit fabffb
	g_return_val_if_fail (self->priv->countries != NULL, NULL);
Packit fabffb
Packit fabffb
	/* Expect only 5 or 6 digit MCCMNC strings */
Packit fabffb
	mccmnc_len = strlen (mccmnc);
Packit fabffb
	if (mccmnc_len != 5 && mccmnc_len != 6)
Packit fabffb
		return NULL;
Packit fabffb
Packit fabffb
	g_hash_table_iter_init (&iter, self->priv->countries);
Packit fabffb
	/* Search through each country */
Packit fabffb
	while (g_hash_table_iter_next (&iter, NULL, &value)) {
Packit fabffb
		NMACountryInfo *country_info = value;
Packit fabffb
Packit fabffb
		/* Search through each country's providers */
Packit fabffb
		for (piter = nma_country_info_get_providers (country_info);
Packit fabffb
		     piter;
Packit fabffb
		     piter = g_slist_next (piter)) {
Packit fabffb
			NMAMobileProvider *provider = piter->data;
Packit fabffb
			const gchar **mccmnc_list;
Packit fabffb
			guint i;
Packit fabffb
Packit fabffb
			/* Search through MCC/MNC list */
Packit fabffb
			mccmnc_list = nma_mobile_provider_get_3gpp_mcc_mnc (provider);
Packit fabffb
			if (!mccmnc_list)
Packit fabffb
				continue;
Packit fabffb
Packit fabffb
			for (i = 0; mccmnc_list[i]; i++) {
Packit fabffb
				const gchar *mccmnc_iter;
Packit fabffb
				guint mccmnc_iter_len;
Packit fabffb
Packit fabffb
				mccmnc_iter = mccmnc_list[i];
Packit fabffb
				mccmnc_iter_len = strlen (mccmnc_iter);
Packit fabffb
Packit fabffb
				/* Match both 2-digit and 3-digit MNC; prefer a
Packit fabffb
				 * 3-digit match if found, otherwise a 2-digit one.
Packit fabffb
				 */
Packit fabffb
Packit fabffb
				if (strncmp (mccmnc_iter, mccmnc, 3))
Packit fabffb
					/* MCC was wrong */
Packit fabffb
					continue;
Packit fabffb
Packit fabffb
				/* Now we have the following match cases, examples given:
Packit fabffb
				 *  a) input: 123/456 --> iter: 123/456 (3-digit match)
Packit fabffb
				 *  b) input: 123/45  --> iter: 123/045 (3-digit match)
Packit fabffb
				 *  c) input: 123/045 --> iter: 123/45  (2-digit match)
Packit fabffb
				 *  d) input: 123/45  --> iter: 123/45  (2-digit match)
Packit fabffb
				 */
Packit fabffb
Packit fabffb
				if (mccmnc_iter_len == 6) {
Packit fabffb
					/* Covers cases a) and b) */
Packit fabffb
					if (   (mccmnc_len == 6 && !strncmp (mccmnc + 3, mccmnc_iter + 3, 3))
Packit fabffb
					    || (mccmnc_len == 5 && mccmnc_iter[3] == '0' && !strncmp (mccmnc + 3, mccmnc_iter + 4, 2)))
Packit fabffb
						/* 3-digit MNC match! */
Packit fabffb
						return provider;
Packit fabffb
Packit fabffb
					/* MNC was wrong */
Packit fabffb
					continue;
Packit fabffb
				}
Packit fabffb
Packit fabffb
				if (   !provider_match_2mnc
Packit fabffb
				    && mccmnc_iter_len == 5) {
Packit fabffb
					if (   (mccmnc_len == 5 && !strncmp (mccmnc + 3, mccmnc_iter + 3, 2))
Packit fabffb
					    || (mccmnc_len == 6 && mccmnc[3] == '0' && !strncmp (mccmnc + 4, mccmnc_iter + 3, 2))) {
Packit fabffb
						/* Store the 2-digit MNC match, but keep looking,
Packit fabffb
						 * we may have a 3-digit MNC match */
Packit fabffb
						provider_match_2mnc = provider;
Packit fabffb
						continue;
Packit fabffb
					}
Packit fabffb
Packit fabffb
					/* MNC was wrong */
Packit fabffb
					continue;
Packit fabffb
				}
Packit fabffb
			}
Packit fabffb
		}
Packit fabffb
	}
Packit fabffb
Packit fabffb
	return provider_match_2mnc;
Packit fabffb
}
Packit fabffb
Packit fabffb
/**
Packit fabffb
 * nma_mobile_providers_database_lookup_cdma_sid:
Packit fabffb
 * @self: a #NMAMobileProvidersDatabase.
Packit fabffb
 * @sid: the SID to look for.
Packit fabffb
 *
Packit fabffb
 * Returns: (transfer none): a #NMAMobileProvider, or %NULL if not found.
Packit fabffb
 */
Packit fabffb
NMAMobileProvider *
Packit fabffb
nma_mobile_providers_database_lookup_cdma_sid (NMAMobileProvidersDatabase *self,
Packit fabffb
                                               guint32 sid)
Packit fabffb
{
Packit fabffb
	GHashTableIter iter;
Packit fabffb
	gpointer value;
Packit fabffb
	GSList *piter;
Packit fabffb
Packit fabffb
	g_return_val_if_fail (NMA_IS_MOBILE_PROVIDERS_DATABASE (self), NULL);
Packit fabffb
	g_return_val_if_fail (sid > 0, NULL);
Packit fabffb
	/* Warn if the object hasn't been initialized */
Packit fabffb
	g_return_val_if_fail (self->priv->countries != NULL, NULL);
Packit fabffb
Packit fabffb
	g_hash_table_iter_init (&iter, self->priv->countries);
Packit fabffb
	/* Search through each country */
Packit fabffb
	while (g_hash_table_iter_next (&iter, NULL, &value)) {
Packit fabffb
		NMACountryInfo *country_info = value;
Packit fabffb
Packit fabffb
		/* Search through each country's providers */
Packit fabffb
		for (piter = nma_country_info_get_providers (country_info);
Packit fabffb
		     piter;
Packit fabffb
		     piter = g_slist_next (piter)) {
Packit fabffb
			NMAMobileProvider *provider = piter->data;
Packit fabffb
			const guint32 *sid_list;
Packit fabffb
			guint i;
Packit fabffb
Packit fabffb
			/* Search through CDMA SID list */
Packit fabffb
			sid_list = nma_mobile_provider_get_cdma_sid (provider);
Packit fabffb
			if (!sid_list)
Packit fabffb
				continue;
Packit fabffb
Packit fabffb
			for (i = 0; sid_list[i]; i++) {
Packit fabffb
				if (sid == sid_list[i])
Packit fabffb
					return provider;
Packit fabffb
			}
Packit fabffb
		}
Packit fabffb
	}
Packit fabffb
Packit fabffb
	return NULL;
Packit fabffb
}
Packit fabffb
Packit fabffb
/**********************************/
Packit fabffb
Packit fabffb
static gboolean
Packit fabffb
initable_init_sync (GInitable     *initable,
Packit fabffb
                    GCancellable  *cancellable,
Packit fabffb
                    GError       **error)
Packit fabffb
{
Packit fabffb
	NMAMobileProvidersDatabase *self = NMA_MOBILE_PROVIDERS_DATABASE (initable);
Packit fabffb
Packit fabffb
	/* Parse the files */
Packit fabffb
	self->priv->countries = mobile_providers_parse_sync (self->priv->country_codes_path,
Packit fabffb
	                                                     self->priv->service_providers_path,
Packit fabffb
	                                                     cancellable,
Packit fabffb
	                                                     error);
Packit fabffb
	if (!self->priv->countries)
Packit fabffb
		return FALSE;
Packit fabffb
Packit fabffb
	/* All good */
Packit fabffb
	return TRUE;
Packit fabffb
}
Packit fabffb
Packit fabffb
/**********************************/
Packit fabffb
Packit fabffb
/**
Packit fabffb
 * nma_mobile_providers_database_new:
Packit fabffb
 * @country_codes: (allow-none): Path to the country codes file.
Packit fabffb
 * @service_providers: (allow-none): Path to the service providers file.
Packit fabffb
 * @cancellable: (allow-none): A #GCancellable or %NULL.
Packit fabffb
 * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
Packit fabffb
 * @user_data: User data to pass to @callback.
Packit fabffb
 *
Packit fabffb
 */
Packit fabffb
void
Packit fabffb
nma_mobile_providers_database_new (const gchar *country_codes,
Packit fabffb
                                   const gchar *service_providers,
Packit fabffb
                                   GCancellable *cancellable,
Packit fabffb
                                   GAsyncReadyCallback callback,
Packit fabffb
                                   gpointer user_data)
Packit fabffb
{
Packit fabffb
	g_async_initable_new_async (NMA_TYPE_MOBILE_PROVIDERS_DATABASE,
Packit fabffb
	                            G_PRIORITY_DEFAULT,
Packit fabffb
	                            cancellable,
Packit fabffb
	                            callback,
Packit fabffb
	                            user_data,
Packit fabffb
	                            "country-codes",     country_codes,
Packit fabffb
	                            "service-providers", service_providers,
Packit fabffb
	                            NULL);
Packit fabffb
}
Packit fabffb
Packit fabffb
/**
Packit fabffb
 * nma_mobile_providers_database_new_finish:
Packit fabffb
 * @res: The #GAsyncResult obtained from the #GAsyncReadyCallback passed to nma_mobile_providers_database_new().
Packit fabffb
 * @error: Return location for error or %NULL.
Packit fabffb
 *
Packit fabffb
 * Returns: (transfer full) (type NMAMobileProvidersDatabase): The constructed object or %NULL if @error is set.
Packit fabffb
 */
Packit fabffb
NMAMobileProvidersDatabase *
Packit fabffb
nma_mobile_providers_database_new_finish (GAsyncResult *res,
Packit fabffb
                                          GError **error)
Packit fabffb
{
Packit fabffb
	GObject *initable;
Packit fabffb
	GObject *out;
Packit fabffb
Packit fabffb
	initable = g_async_result_get_source_object (res);
Packit fabffb
	out = g_async_initable_new_finish (G_ASYNC_INITABLE (initable), res, error);
Packit fabffb
	g_object_unref (initable);
Packit fabffb
Packit fabffb
	return out ? NMA_MOBILE_PROVIDERS_DATABASE (out) : NULL;
Packit fabffb
}
Packit fabffb
Packit fabffb
/**
Packit fabffb
 * nma_mobile_providers_database_new_sync:
Packit fabffb
 * @country_codes: (allow-none): Path to the country codes file.
Packit fabffb
 * @service_providers: (allow-none): Path to the service providers file.
Packit fabffb
 * @cancellable: (allow-none): A #GCancellable or %NULL.
Packit fabffb
 * @error: Return location for error or %NULL.
Packit fabffb
 *
Packit fabffb
 * Returns: (transfer full) (type NMAMobileProvidersDatabase): The constructed object or %NULL if @error is set.
Packit fabffb
 */
Packit fabffb
NMAMobileProvidersDatabase *
Packit fabffb
nma_mobile_providers_database_new_sync (const gchar *country_codes,
Packit fabffb
                                        const gchar *service_providers,
Packit fabffb
                                        GCancellable *cancellable,
Packit fabffb
                                        GError **error)
Packit fabffb
{
Packit fabffb
	GObject *out;
Packit fabffb
Packit fabffb
	out = g_initable_new (NMA_TYPE_MOBILE_PROVIDERS_DATABASE,
Packit fabffb
	                      cancellable,
Packit fabffb
	                      error,
Packit fabffb
	                      "country-codes",     country_codes,
Packit fabffb
	                      "service-providers", service_providers,
Packit fabffb
	                      NULL);
Packit fabffb
Packit fabffb
	return out ? NMA_MOBILE_PROVIDERS_DATABASE (out) : NULL;
Packit fabffb
}
Packit fabffb
Packit fabffb
/**********************************/
Packit fabffb
Packit fabffb
static void
Packit fabffb
set_property (GObject *object,
Packit fabffb
              guint prop_id,
Packit fabffb
              const GValue *value,
Packit fabffb
              GParamSpec *pspec)
Packit fabffb
{
Packit fabffb
	NMAMobileProvidersDatabase *self = NMA_MOBILE_PROVIDERS_DATABASE (object);
Packit fabffb
Packit fabffb
	switch (prop_id) {
Packit fabffb
	case PROP_COUNTRY_CODES_PATH:
Packit fabffb
		self->priv->country_codes_path = g_value_dup_string (value);
Packit fabffb
		break;
Packit fabffb
	case PROP_SERVICE_PROVIDERS_PATH:
Packit fabffb
		self->priv->service_providers_path = g_value_dup_string (value);
Packit fabffb
		break;
Packit fabffb
	default:
Packit fabffb
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit fabffb
		break;
Packit fabffb
	}
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
get_property (GObject *object,
Packit fabffb
              guint prop_id,
Packit fabffb
              GValue *value,
Packit fabffb
              GParamSpec *pspec)
Packit fabffb
{
Packit fabffb
	NMAMobileProvidersDatabase *self = NMA_MOBILE_PROVIDERS_DATABASE (object);
Packit fabffb
Packit fabffb
	switch (prop_id) {
Packit fabffb
	case PROP_COUNTRY_CODES_PATH:
Packit fabffb
		g_value_set_string (value, self->priv->country_codes_path);
Packit fabffb
		break;
Packit fabffb
	case PROP_SERVICE_PROVIDERS_PATH:
Packit fabffb
		g_value_set_string (value, self->priv->service_providers_path);
Packit fabffb
		break;
Packit fabffb
	default:
Packit fabffb
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit fabffb
		break;
Packit fabffb
	}
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
nma_mobile_providers_database_init (NMAMobileProvidersDatabase *self)
Packit fabffb
{
Packit fabffb
	/* Setup private data */
Packit fabffb
	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
Packit fabffb
	                                          NMA_TYPE_MOBILE_PROVIDERS_DATABASE,
Packit fabffb
	                                          NMAMobileProvidersDatabasePrivate);
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
finalize (GObject *object)
Packit fabffb
{
Packit fabffb
	NMAMobileProvidersDatabase *self = NMA_MOBILE_PROVIDERS_DATABASE (object);
Packit fabffb
Packit fabffb
	g_free (self->priv->country_codes_path);
Packit fabffb
	g_free (self->priv->service_providers_path);
Packit fabffb
Packit fabffb
	if (self->priv->countries)
Packit fabffb
		g_hash_table_unref (self->priv->countries);
Packit fabffb
Packit fabffb
	G_OBJECT_CLASS (nma_mobile_providers_database_parent_class)->finalize (object);
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
initable_iface_init (GInitableIface *iface)
Packit fabffb
{
Packit fabffb
	iface->init = initable_init_sync;
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
async_initable_iface_init (GAsyncInitableIface *iface)
Packit fabffb
{
Packit fabffb
	/* Just use defaults (run sync init() in a thread) */
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
nma_mobile_providers_database_class_init (NMAMobileProvidersDatabaseClass *klass)
Packit fabffb
{
Packit fabffb
    GObjectClass *object_class = G_OBJECT_CLASS (klass);
Packit fabffb
Packit fabffb
    g_type_class_add_private (object_class, sizeof (NMAMobileProvidersDatabasePrivate));
Packit fabffb
Packit fabffb
    /* Virtual methods */
Packit fabffb
    object_class->get_property = get_property;
Packit fabffb
    object_class->set_property = set_property;
Packit fabffb
    object_class->finalize = finalize;
Packit fabffb
Packit fabffb
    properties[PROP_COUNTRY_CODES_PATH] =
Packit fabffb
	    g_param_spec_string ("country-codes",
Packit fabffb
                             "Country Codes",
Packit fabffb
                             "Path to the country codes file",
Packit fabffb
	                         NULL,
Packit fabffb
                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
Packit fabffb
    g_object_class_install_property (object_class, PROP_COUNTRY_CODES_PATH, properties[PROP_COUNTRY_CODES_PATH]);
Packit fabffb
Packit fabffb
    properties[PROP_SERVICE_PROVIDERS_PATH] =
Packit fabffb
	    g_param_spec_string ("service-providers",
Packit fabffb
	                         "Service Providers",
Packit fabffb
	                         "Path to the service providers file",
Packit fabffb
	                         NULL,
Packit fabffb
	                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
Packit fabffb
    g_object_class_install_property (object_class, PROP_SERVICE_PROVIDERS_PATH, properties[PROP_SERVICE_PROVIDERS_PATH]);
Packit fabffb
}
Packit fabffb
Packit fabffb
/******************************************************************************/
Packit fabffb
/* Utils */
Packit fabffb
Packit fabffb
/**
Packit fabffb
 * nma_mobile_providers_split_3gpp_mcc_mnc:
Packit fabffb
 * @mccmnc: input MCCMNC string.
Packit fabffb
 * @mcc: (out) (transfer full): the MCC.
Packit fabffb
 * @mnc: (out) (transfer full): the MNC.
Packit fabffb
 *
Packit fabffb
 * Splits the input MCCMNC string into separate MCC and MNC strings.
Packit fabffb
 *
Packit fabffb
 * Returns: %TRUE if correctly split and @mcc and @mnc are set; %FALSE otherwise.
Packit fabffb
 */
Packit fabffb
gboolean
Packit fabffb
nma_mobile_providers_split_3gpp_mcc_mnc (const gchar *mccmnc,
Packit fabffb
                                         gchar **mcc,
Packit fabffb
                                         gchar **mnc)
Packit fabffb
{
Packit fabffb
	gint len;
Packit fabffb
Packit fabffb
	g_return_val_if_fail (mccmnc != NULL, FALSE);
Packit fabffb
	g_return_val_if_fail (mcc != NULL, FALSE);
Packit fabffb
	g_return_val_if_fail (mnc != NULL, FALSE);
Packit fabffb
Packit fabffb
	len = strlen (mccmnc);
Packit fabffb
	if (len != 5 && len != 6)
Packit fabffb
		return FALSE;
Packit fabffb
Packit fabffb
	/* MCCMNC is all digits */
Packit fabffb
	while (len > 0) {
Packit fabffb
		if (!g_ascii_isdigit (mccmnc[--len]))
Packit fabffb
			return FALSE;
Packit fabffb
	}
Packit fabffb
Packit fabffb
	*mcc = g_strndup (mccmnc, 3);
Packit fabffb
	*mnc = g_strdup (mccmnc + 3);
Packit fabffb
	return TRUE;
Packit fabffb
}