mobile-providers: use libnm-gtk to work with mobile providers

This commit removes all the code in charge of playing with the database of
mobile providers, which was originally included in order to perform
MCCMNC->OperatorName and SID->OperatorName conversions.

This logic is now exposed by libnm-gtk.

https://bugzilla.gnome.org/show_bug.cgi?id=688943
This commit is contained in:
Aleksander Morgado 2012-11-23 16:46:49 +01:00
parent 393a3a079f
commit 8dd880d0c8
8 changed files with 39 additions and 1240 deletions

View File

@ -2,73 +2,37 @@
const Gio = imports.gi.Gio; const Gio = imports.gi.Gio;
const Lang = imports.lang; const Lang = imports.lang;
const Shell = imports.gi.Shell; const NMGtk = imports.gi.NMGtk;
const Signals = imports.signals; const Signals = imports.signals;
// _getMobileProvidersDatabase:
// _getProvidersTable:
// //
// Gets the table of references between MCCMNC and operator name // Gets the database of mobile providers, with references between MCCMNC/SID and
// operator name
// //
let _providersTable; let _mpd;
function _getProvidersTable() { function _getMobileProvidersDatabase() {
if (_providersTable) if (_mpd == null) {
return _providersTable; try {
return _providersTable = Shell.mobile_providers_parse(null,null); _mpd = new NMGtk.MobileProvidersDatabase();
} _mpd.init(null);
} catch (e) {
// findProviderForMCCMNC: log(e.message);
// @table: a table of country code keys and Shell.CountryMobileProvider values _mpd = null;
// @needle: operator code, given as MCCMNC string
//
// Tries to find the operator name corresponding to the given MCCMNC
//
function findProviderForMCCMNC(table, needle) {
let needlemcc = needle.substring(0, 3);
let needlemnc = needle.substring(3, needle.length);
let name2, name3;
for (let iter in table) {
let country = table[iter];
let providers = country.get_providers();
// Search through each country's providers
for (let i = 0; i < providers.length; i++) {
let provider = providers[i];
// Search through MCC/MNC list
let list = provider.get_gsm_mcc_mnc();
for (let j = 0; j < list.length; j++) {
let mccmnc = list[j];
// Match both 2-digit and 3-digit MNC; prefer a
// 3-digit match if found, otherwise a 2-digit one.
if (mccmnc.mcc != needlemcc)
continue; // MCC was wrong
if (!name3 && needle.length == 6 && needlemnc == mccmnc.mnc)
name3 = provider.name;
if (!name2 && needlemnc.substring(0, 2) == mccmnc.mnc.substring(0, 2))
name2 = provider.name;
if (name2 && name3)
break;
}
} }
} }
return name3 || name2 || null; return _mpd;
} }
// findOperatorName: // _findProviderForMccMnc:
// @operator_name: operator name // @operator_name: operator name
// @operator_code: operator code // @operator_code: operator code
// //
// Given an operator name string (which may not be a real operator name) and an // Given an operator name string (which may not be a real operator name) and an
// operator code string, tries to find a proper operator name to display. // operator code string, tries to find a proper operator name to display.
// //
function findOperatorName(operator_name, operator_code) { function _findProviderForMccMnc(operator_name, operator_code) {
if (operator_name) { if (operator_name) {
if (operator_name.length != 0 && if (operator_name.length != 0 &&
(operator_name.length > 6 || operator_name.length < 5)) { (operator_name.length > 6 || operator_name.length < 5)) {
@ -92,41 +56,34 @@ function findOperatorName(operator_name, operator_code) {
else // nothing to search else // nothing to search
return null; return null;
let table = _getProvidersTable(); let mpd = _getMobileProvidersDatabase();
return findProviderForMCCMNC(table, needle); if (mpd) {
let provider = mpd.lookup_3gpp_mcc_mnc(needle);
if (provider)
return provider.get_name();
}
return null;
} }
// findProviderForSid: // _findProviderForSid:
// @table: a table of country code keys and Shell.CountryMobileProvider values
// @sid: System Identifier of the serving CDMA network // @sid: System Identifier of the serving CDMA network
// //
// Tries to find the operator name corresponding to the given SID // Tries to find the operator name corresponding to the given SID
// //
function findProviderForSid(table, sid) { function _findProviderForSid(sid) {
if (sid == 0) if (sid == 0)
return null; return null;
// Search through each country let mpd = _getMobileProvidersDatabase();
for (let iter in table) { if (mpd) {
let country = table[iter]; let provider = mpd.lookup_cdma_sid(sid);
let providers = country.get_providers(); if (provider)
return provider.get_name();
// Search through each country's providers
for (let i = 0; i < providers.length; i++) {
let provider = providers[i];
let cdma_sid = provider.get_cdma_sid();
// Search through CDMA SID list
for (let j = 0; j < cdma_sid.length; j++) {
if (cdma_sid[j] == sid)
return provider.name;
}
}
} }
return null; return null;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Support for the old ModemManager interface (MM < 0.7) // Support for the old ModemManager interface (MM < 0.7)
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -184,7 +141,7 @@ const ModemGsm = new Lang.Class({
this.emit('notify::signal-quality'); this.emit('notify::signal-quality');
})); }));
this._proxy.connectSignal('RegistrationInfo', Lang.bind(this, function(proxy, sender, [status, code, name]) { this._proxy.connectSignal('RegistrationInfo', Lang.bind(this, function(proxy, sender, [status, code, name]) {
this.operator_name = findOperatorName(name, code); this.operator_name = _findProviderForMccMnc(name, code);
this.emit('notify::operator-name'); this.emit('notify::operator-name');
})); }));
this._proxy.GetRegistrationInfoRemote(Lang.bind(this, function([result], err) { this._proxy.GetRegistrationInfoRemote(Lang.bind(this, function([result], err) {
@ -194,7 +151,7 @@ const ModemGsm = new Lang.Class({
} }
let [status, code, name] = result; let [status, code, name] = result;
this.operator_name = findOperatorName(name, code); this.operator_name = _findProviderForMccMnc(name, code);
this.emit('notify::operator-name'); this.emit('notify::operator-name');
})); }));
this._proxy.GetSignalQualityRemote(Lang.bind(this, function(result, err) { this._proxy.GetSignalQualityRemote(Lang.bind(this, function(result, err) {
@ -246,12 +203,9 @@ const ModemCdma = new Lang.Class({
// it will return an error if the device is not connected // it will return an error if the device is not connected
this.operator_name = null; this.operator_name = null;
} else { } else {
let [bandClass, band, id] = result; let [bandClass, band, sid] = result;
if (name.length > 0) {
let table = _getProvidersTable(); this.operator_name = _findProviderForSid(sid)
this.operator_name = findProviderForSid(table, id);
} else
this.operator_name = null;
} }
this.emit('notify::operator-name'); this.emit('notify::operator-name');
})); }));
@ -334,13 +288,13 @@ const BroadbandModem = new Lang.Class({
_reload3gppOperatorName: function() { _reload3gppOperatorName: function() {
let name = this._proxy_3gpp.OperatorName; let name = this._proxy_3gpp.OperatorName;
let code = this._proxy_3gpp.OperatorCode; let code = this._proxy_3gpp.OperatorCode;
this.operator_name_3gpp = findOperatorName(name, code); this.operator_name_3gpp = _findProviderForMccMnc(name, code);
this._reloadOperatorName(); this._reloadOperatorName();
}, },
_reloadCdmaOperatorName: function() { _reloadCdmaOperatorName: function() {
let sid = this._proxy_cdma.Sid; let sid = this._proxy_cdma.Sid;
this.operator_name_cdma = findProviderForSid(sid); this.operator_name_cdma = _findProviderForSid(sid);
this._reloadOperatorName(); this._reloadOperatorName();
} }
}); });

View File

@ -115,7 +115,6 @@ shell_public_headers_h = \
shell-global.h \ shell-global.h \
shell-invert-lightness-effect.h \ shell-invert-lightness-effect.h \
shell-keybinding-modes.h \ shell-keybinding-modes.h \
shell-mobile-providers.h \
shell-mount-operation.h \ shell-mount-operation.h \
shell-network-agent.h \ shell-network-agent.h \
shell-perf-log.h \ shell-perf-log.h \
@ -160,7 +159,6 @@ libgnome_shell_la_SOURCES = \
shell-invert-lightness-effect.c \ shell-invert-lightness-effect.c \
shell-keyring-prompt.h \ shell-keyring-prompt.h \
shell-keyring-prompt.c \ shell-keyring-prompt.c \
shell-mobile-providers.c \
shell-mount-operation.c \ shell-mount-operation.c \
shell-network-agent.c \ shell-network-agent.c \
shell-perf-log.c \ shell-perf-log.c \

View File

@ -1,914 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* Copyright (C) 2009 Novell, Inc.
* Author: Tambet Ingo (tambet@gmail.com).
*
* Copyright (C) 2009 - 2010 Red Hat, Inc.
*/
#include "config.h"
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <glib/gi18n.h>
#include "shell-mobile-providers.h"
#ifndef MOBILE_BROADBAND_PROVIDER_INFO
#define MOBILE_BROADBAND_PROVIDER_INFO DATADIR "/mobile-broadband-provider-info/serviceproviders.xml"
#endif
#define ISO_3166_COUNTRY_CODES DATADIR "/zoneinfo/iso3166.tab"
static ShellCountryMobileProvider *country_mobile_provider_new (const char *country_code,
const gchar *country_name);
static GHashTable *
read_country_codes (const gchar *country_codes)
{
GHashTable *table;
GIOChannel *channel;
GString *buffer;
GError *error = NULL;
GIOStatus status;
channel = g_io_channel_new_file (country_codes, "r", &error);
if (!channel) {
if (error) {
g_warning ("Could not read %s: %s", country_codes, error->message);
g_error_free (error);
} else
g_warning ("Could not read %s: Unknown error", country_codes);
return NULL;
}
table = g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
(GDestroyNotify)shell_country_mobile_provider_unref);
buffer = g_string_sized_new (32);
status = G_IO_STATUS_NORMAL;
while (status == G_IO_STATUS_NORMAL) {
status = g_io_channel_read_line_string (channel, buffer, NULL, &error);
switch (status) {
case G_IO_STATUS_NORMAL:
if (buffer->str[0] != '#') {
ShellCountryMobileProvider *country_provider;
char **pieces;
pieces = g_strsplit (buffer->str, "\t", 2);
/* Hack for rh#556292; iso3166.tab is just wrong */
pieces[1] = pieces[1] ? g_strchomp (pieces[1]) : NULL;
if (pieces[1] && !strcmp (pieces[1], "Britain (UK)")) {
g_free (pieces[1]);
pieces[1] = g_strdup (_("United Kingdom"));
}
country_provider = country_mobile_provider_new (pieces[0], pieces[1]);
g_hash_table_insert (table, pieces[0], country_provider);
g_free (pieces);
}
g_string_truncate (buffer, 0);
break;
case G_IO_STATUS_EOF:
break;
case G_IO_STATUS_ERROR:
g_warning ("Error while reading: %s", error->message);
g_error_free (error);
break;
case G_IO_STATUS_AGAIN:
/* FIXME: Try again a few times, but really, it never happes, right? */
break;
}
}
g_string_free (buffer, TRUE);
g_io_channel_unref (channel);
return table;
}
/* XML Parser */
typedef enum {
PARSER_TOPLEVEL = 0,
PARSER_COUNTRY,
PARSER_PROVIDER,
PARSER_METHOD_GSM,
PARSER_METHOD_GSM_APN,
PARSER_METHOD_CDMA,
PARSER_ERROR
} MobileContextState;
typedef struct {
GHashTable *table;
char *current_country;
GSList *current_providers;
ShellMobileProvider *current_provider;
ShellMobileAccessMethod *current_method;
char *text_buffer;
MobileContextState state;
} MobileParser;
static ShellGsmMccMnc *
mcc_mnc_new (const char *mcc, const char *mnc)
{
ShellGsmMccMnc *m;
m = g_slice_new (ShellGsmMccMnc);
m->mcc = g_strstrip (g_strdup (mcc));
m->mnc = g_strstrip (g_strdup (mnc));
return m;
}
/* added in porting */
static ShellGsmMccMnc *
mcc_mnc_copy (const ShellGsmMccMnc *other) {
ShellGsmMccMnc *ret;
ret = g_slice_new (ShellGsmMccMnc);
ret->mcc = g_strdup (other->mcc);
ret->mnc = g_strdup (other->mnc);
return ret;
}
static void
mcc_mnc_free (ShellGsmMccMnc *m)
{
g_return_if_fail (m != NULL);
g_free (m->mcc);
g_free (m->mnc);
g_slice_free (ShellGsmMccMnc, m);
}
/* added in porting */
G_DEFINE_BOXED_TYPE (ShellGsmMccMnc, shell_gsm_mcc_mnc, mcc_mnc_copy, mcc_mnc_free)
static ShellMobileAccessMethod *
access_method_new (void)
{
ShellMobileAccessMethod *method;
method = g_slice_new0 (ShellMobileAccessMethod);
method->refs = 1;
method->lcl_names = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify) g_free,
(GDestroyNotify) g_free);
return method;
}
ShellMobileAccessMethod *
shell_mobile_access_method_ref (ShellMobileAccessMethod *method)
{
g_return_val_if_fail (method != NULL, NULL);
g_return_val_if_fail (method->refs > 0, NULL);
method->refs++;
return method;
}
void
shell_mobile_access_method_unref (ShellMobileAccessMethod *method)
{
g_return_if_fail (method != NULL);
g_return_if_fail (method->refs > 0);
if (--method->refs == 0) {
g_free (method->name);
g_hash_table_destroy (method->lcl_names);
g_free (method->username);
g_free (method->password);
g_free (method->gateway);
g_free (method->gsm_apn);
g_slist_foreach (method->dns, (GFunc) g_free, NULL);
g_slist_free (method->dns);
g_slice_free (ShellMobileAccessMethod, method);
}
}
GType
shell_mobile_access_method_get_type (void)
{
static GType type = 0;
if (G_UNLIKELY (type == 0)) {
type = g_boxed_type_register_static ("ShellMobileAccessMethod",
(GBoxedCopyFunc) shell_mobile_access_method_ref,
(GBoxedFreeFunc) shell_mobile_access_method_unref);
}
return type;
}
static ShellMobileProvider *
provider_new (void)
{
ShellMobileProvider *provider;
provider = g_slice_new0 (ShellMobileProvider);
provider->refs = 1;
provider->lcl_names = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify) g_free,
(GDestroyNotify) g_free);
return provider;
}
ShellMobileProvider *
shell_mobile_provider_ref (ShellMobileProvider *provider)
{
provider->refs++;
return provider;
}
void
shell_mobile_provider_unref (ShellMobileProvider *provider)
{
if (--provider->refs == 0) {
g_free (provider->name);
g_hash_table_destroy (provider->lcl_names);
g_slist_foreach (provider->methods, (GFunc) shell_mobile_access_method_unref, NULL);
g_slist_free (provider->methods);
g_slist_foreach (provider->gsm_mcc_mnc, (GFunc) mcc_mnc_free, NULL);
g_slist_free (provider->gsm_mcc_mnc);
g_slist_free (provider->cdma_sid);
g_slice_free (ShellMobileProvider, provider);
}
}
GType
shell_mobile_provider_get_type (void)
{
static GType type = 0;
if (G_UNLIKELY (type == 0)) {
type = g_boxed_type_register_static ("ShellMobileProvider",
(GBoxedCopyFunc) shell_mobile_provider_ref,
(GBoxedFreeFunc) shell_mobile_provider_unref);
}
return type;
}
static ShellCountryMobileProvider *
country_mobile_provider_new (const char *country_code,
const gchar *country_name)
{
ShellCountryMobileProvider *country_provider;
country_provider = g_slice_new0 (ShellCountryMobileProvider);
country_provider->refs = 1;
country_provider->country_code = g_strdup (country_code);
country_provider->country_name = g_strdup (country_name);
return country_provider;
}
ShellCountryMobileProvider *
shell_country_mobile_provider_ref (ShellCountryMobileProvider *country_provider)
{
country_provider->refs++;
return country_provider;
}
void
shell_country_mobile_provider_unref (ShellCountryMobileProvider *country_provider)
{
if (--country_provider->refs == 0) {
g_free (country_provider->country_code);
g_free (country_provider->country_name);
g_slist_free_full (country_provider->providers,
(GDestroyNotify) shell_mobile_provider_unref);
g_slice_free (ShellCountryMobileProvider, country_provider);
}
}
/**
* shell_country_mobile_provider_get_country_code:
*
* Returns: (transfer none): the code of the country.
*/
const gchar *
shell_country_mobile_provider_get_country_code (ShellCountryMobileProvider *country_provider)
{
return country_provider->country_code;
}
/**
* shell_country_mobile_provider_get_country_name:
*
* Returns: (transfer none): the name of the country.
*/
const gchar *
shell_country_mobile_provider_get_country_name (ShellCountryMobileProvider *country_provider)
{
return country_provider->country_name;
}
/**
* shell_country_mobile_provider_get_providers:
*
* Returns: (element-type Shell.MobileProvider) (transfer none): the
* list of #ShellMobileProvider this country exposes.
*/
GSList *
shell_country_mobile_provider_get_providers (ShellCountryMobileProvider *country_provider)
{
return country_provider->providers;
}
GType
shell_country_mobile_provider_get_type (void)
{
static GType type = 0;
if (G_UNLIKELY (type == 0)) {
type = g_boxed_type_register_static ("ShellCountryMobileProvider",
(GBoxedCopyFunc) shell_country_mobile_provider_ref,
(GBoxedFreeFunc) shell_country_mobile_provider_unref);
}
return type;
}
static void
provider_list_free (gpointer data)
{
GSList *list = (GSList *) data;
while (list) {
shell_mobile_provider_unref ((ShellMobileProvider *) list->data);
list = g_slist_delete_link (list, list);
}
}
static void
parser_toplevel_start (MobileParser *parser,
const char *name,
const char **attribute_names,
const char **attribute_values)
{
int i;
if (!strcmp (name, "serviceproviders")) {
for (i = 0; attribute_names && attribute_names[i]; i++) {
if (!strcmp (attribute_names[i], "format")) {
if (strcmp (attribute_values[i], "2.0")) {
g_warning ("%s: mobile broadband provider database format '%s'"
" not supported.", __func__, attribute_values[i]);
parser->state = PARSER_ERROR;
break;
}
}
}
} else if (!strcmp (name, "country")) {
for (i = 0; attribute_names && attribute_names[i]; i++) {
if (!strcmp (attribute_names[i], "code")) {
char *country_code;
ShellCountryMobileProvider *country_provider;
country_code = g_ascii_strup (attribute_values[i], -1);
country_provider = g_hash_table_lookup (parser->table, country_code);
/* Ensure we have a country provider for this country code */
if (!country_provider) {
g_warning ("%s: adding providers for unknown country '%s'", __func__, country_code);
country_provider = country_mobile_provider_new (country_code, NULL);
g_hash_table_insert (parser->table, country_code, country_provider);
}
parser->current_country = country_code;
parser->state = PARSER_COUNTRY;
break;
}
}
}
}
static void
parser_country_start (MobileParser *parser,
const char *name,
const char **attribute_names,
const char **attribute_values)
{
if (!strcmp (name, "provider")) {
parser->state = PARSER_PROVIDER;
parser->current_provider = provider_new ();
}
}
static void
parser_provider_start (MobileParser *parser,
const char *name,
const char **attribute_names,
const char **attribute_values)
{
if (!strcmp (name, "gsm"))
parser->state = PARSER_METHOD_GSM;
else if (!strcmp (name, "cdma")) {
parser->state = PARSER_METHOD_CDMA;
parser->current_method = access_method_new ();
}
}
static void
parser_gsm_start (MobileParser *parser,
const char *name,
const char **attribute_names,
const char **attribute_values)
{
if (!strcmp (name, "network-id")) {
const char *mcc = NULL, *mnc = NULL;
int i;
for (i = 0; attribute_names && attribute_names[i]; i++) {
if (!strcmp (attribute_names[i], "mcc"))
mcc = attribute_values[i];
else if (!strcmp (attribute_names[i], "mnc"))
mnc = attribute_values[i];
if (mcc && strlen (mcc) && mnc && strlen (mnc)) {
parser->current_provider->gsm_mcc_mnc = g_slist_prepend (parser->current_provider->gsm_mcc_mnc,
mcc_mnc_new (mcc, mnc));
break;
}
}
} else if (!strcmp (name, "apn")) {
int i;
for (i = 0; attribute_names && attribute_names[i]; i++) {
if (!strcmp (attribute_names[i], "value")) {
parser->state = PARSER_METHOD_GSM_APN;
parser->current_method = access_method_new ();
parser->current_method->gsm_apn = g_strstrip (g_strdup (attribute_values[i]));
break;
}
}
}
}
static void
parser_cdma_start (MobileParser *parser,
const char *name,
const char **attribute_names,
const char **attribute_values)
{
if (!strcmp (name, "sid")) {
int i;
for (i = 0; attribute_names && attribute_names[i]; i++) {
if (!strcmp (attribute_names[i], "value")) {
unsigned long tmp;
errno = 0;
tmp = strtoul (attribute_values[i], NULL, 10);
if (errno == 0 && tmp > 0)
parser->current_provider->cdma_sid = g_slist_prepend (parser->current_provider->cdma_sid,
GUINT_TO_POINTER ((guint32) tmp));
break;
}
}
}
}
static void
mobile_parser_start_element (GMarkupParseContext *context,
const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
gpointer data,
GError **error)
{
MobileParser *parser = (MobileParser *) data;
if (parser->text_buffer) {
g_free (parser->text_buffer);
parser->text_buffer = NULL;
}
switch (parser->state) {
case PARSER_TOPLEVEL:
parser_toplevel_start (parser, element_name, attribute_names, attribute_values);
break;
case PARSER_COUNTRY:
parser_country_start (parser, element_name, attribute_names, attribute_values);
break;
case PARSER_PROVIDER:
parser_provider_start (parser, element_name, attribute_names, attribute_values);
break;
case PARSER_METHOD_GSM:
parser_gsm_start (parser, element_name, attribute_names, attribute_values);
break;
case PARSER_METHOD_CDMA:
parser_cdma_start (parser, element_name, attribute_names, attribute_values);
break;
default:
break;
}
}
static void
parser_country_end (MobileParser *parser,
const char *name)
{
if (!strcmp (name, "country")) {
ShellCountryMobileProvider *country_provider;
country_provider = g_hash_table_lookup (parser->table, parser->current_country);
if (country_provider)
/* Store providers for this country */
country_provider->providers = parser->current_providers;
parser->current_country = NULL;
parser->current_providers = NULL;
parser->text_buffer = NULL;
parser->state = PARSER_TOPLEVEL;
}
}
static void
parser_provider_end (MobileParser *parser,
const char *name)
{
if (!strcmp (name, "name")) {
if (!parser->current_provider->name) {
/* Use the first one. */
parser->current_provider->name = parser->text_buffer;
parser->text_buffer = NULL;
}
} else if (!strcmp (name, "provider")) {
parser->current_provider->methods = g_slist_reverse (parser->current_provider->methods);
parser->current_provider->gsm_mcc_mnc = g_slist_reverse (parser->current_provider->gsm_mcc_mnc);
parser->current_provider->cdma_sid = g_slist_reverse (parser->current_provider->cdma_sid);
parser->current_providers = g_slist_prepend (parser->current_providers, parser->current_provider);
parser->current_provider = NULL;
parser->text_buffer = NULL;
parser->state = PARSER_COUNTRY;
}
}
static void
parser_gsm_end (MobileParser *parser,
const char *name)
{
if (!strcmp (name, "gsm")) {
parser->text_buffer = NULL;
parser->state = PARSER_PROVIDER;
}
}
static void
parser_gsm_apn_end (MobileParser *parser,
const char *name)
{
if (!strcmp (name, "name")) {
if (!parser->current_method->name) {
/* Use the first one. */
parser->current_method->name = parser->text_buffer;
parser->text_buffer = NULL;
}
} else if (!strcmp (name, "username")) {
parser->current_method->username = parser->text_buffer;
parser->text_buffer = NULL;
} else if (!strcmp (name, "password")) {
parser->current_method->password = parser->text_buffer;
parser->text_buffer = NULL;
} else if (!strcmp (name, "dns")) {
parser->current_method->dns = g_slist_prepend (parser->current_method->dns, parser->text_buffer);
parser->text_buffer = NULL;
} else if (!strcmp (name, "gateway")) {
parser->current_method->gateway = parser->text_buffer;
parser->text_buffer = NULL;
} else if (!strcmp (name, "apn")) {
parser->current_method->type = SHELL_MOBILE_ACCESS_METHOD_TYPE_GSM;
parser->current_method->dns = g_slist_reverse (parser->current_method->dns);
if (!parser->current_method->name)
parser->current_method->name = g_strdup (_("Default"));
parser->current_provider->methods = g_slist_prepend (parser->current_provider->methods,
parser->current_method);
parser->current_method = NULL;
parser->text_buffer = NULL;
parser->state = PARSER_METHOD_GSM;
}
}
static void
parser_cdma_end (MobileParser *parser,
const char *name)
{
if (!strcmp (name, "username")) {
parser->current_method->username = parser->text_buffer;
parser->text_buffer = NULL;
} else if (!strcmp (name, "password")) {
parser->current_method->password = parser->text_buffer;
parser->text_buffer = NULL;
} else if (!strcmp (name, "dns")) {
parser->current_method->dns = g_slist_prepend (parser->current_method->dns, parser->text_buffer);
parser->text_buffer = NULL;
} else if (!strcmp (name, "gateway")) {
parser->current_method->gateway = parser->text_buffer;
parser->text_buffer = NULL;
} else if (!strcmp (name, "cdma")) {
parser->current_method->type = SHELL_MOBILE_ACCESS_METHOD_TYPE_CDMA;
parser->current_method->dns = g_slist_reverse (parser->current_method->dns);
if (!parser->current_method->name)
parser->current_method->name = g_strdup (parser->current_provider->name);
parser->current_provider->methods = g_slist_prepend (parser->current_provider->methods,
parser->current_method);
parser->current_method = NULL;
parser->text_buffer = NULL;
parser->state = PARSER_PROVIDER;
}
}
static void
mobile_parser_end_element (GMarkupParseContext *context,
const gchar *element_name,
gpointer data,
GError **error)
{
MobileParser *parser = (MobileParser *) data;
switch (parser->state) {
case PARSER_COUNTRY:
parser_country_end (parser, element_name);
break;
case PARSER_PROVIDER:
parser_provider_end (parser, element_name);
break;
case PARSER_METHOD_GSM:
parser_gsm_end (parser, element_name);
break;
case PARSER_METHOD_GSM_APN:
parser_gsm_apn_end (parser, element_name);
break;
case PARSER_METHOD_CDMA:
parser_cdma_end (parser, element_name);
break;
default:
break;
}
}
static void
mobile_parser_characters (GMarkupParseContext *context,
const gchar *text,
gsize text_len,
gpointer data,
GError **error)
{
MobileParser *parser = (MobileParser *) data;
g_free (parser->text_buffer);
parser->text_buffer = g_strdup (text);
}
static const GMarkupParser mobile_parser = {
mobile_parser_start_element,
mobile_parser_end_element,
mobile_parser_characters,
NULL, /* passthrough */
NULL /* error */
};
/**
* shell_mobile_providers_parse:
* @country_codes: (allow-none) File with the list of country codes.
* @service_providers: (allow-none) File with the list of service providers.
*
* Returns: (element-type utf8 Shell.CountryMobileProvider) (transfer full): a
* hash table where keys are country names #gchar and values are #ShellCountryMobileProvider.
* Everything is destroyed with g_hash_table_destroy().
*/
GHashTable *
shell_mobile_providers_parse (const gchar *country_codes,
const gchar *service_providers)
{
GMarkupParseContext *ctx;
GIOChannel *channel;
MobileParser parser;
GError *error = NULL;
char buffer[4096];
GIOStatus status;
gsize len = 0;
/* Use default paths if none given */
if (!country_codes)
country_codes = ISO_3166_COUNTRY_CODES;
if (!service_providers)
service_providers = MOBILE_BROADBAND_PROVIDER_INFO;
memset (&parser, 0, sizeof (MobileParser));
parser.table = read_country_codes (country_codes);
if (!parser.table)
goto out;
channel = g_io_channel_new_file (service_providers, "r", &error);
if (!channel) {
if (error) {
g_warning ("Could not read %s: %s", service_providers, error->message);
g_error_free (error);
} else
g_warning ("Could not read %s: Unknown error", service_providers);
goto out;
}
parser.state = PARSER_TOPLEVEL;
ctx = g_markup_parse_context_new (&mobile_parser, 0, &parser, NULL);
status = G_IO_STATUS_NORMAL;
while (status == G_IO_STATUS_NORMAL) {
status = g_io_channel_read_chars (channel, buffer, sizeof (buffer), &len, &error);
switch (status) {
case G_IO_STATUS_NORMAL:
if (!g_markup_parse_context_parse (ctx, buffer, len, &error)) {
status = G_IO_STATUS_ERROR;
g_warning ("Error while parsing XML: %s", error->message);
g_error_free (error);;
}
break;
case G_IO_STATUS_EOF:
break;
case G_IO_STATUS_ERROR:
g_warning ("Error while reading: %s", error->message);
g_error_free (error);
break;
case G_IO_STATUS_AGAIN:
/* FIXME: Try again a few times, but really, it never happes, right? */
break;
}
}
g_io_channel_unref (channel);
g_markup_parse_context_free (ctx);
if (parser.current_provider) {
g_warning ("pending current provider");
shell_mobile_provider_unref (parser.current_provider);
}
if (parser.current_providers) {
g_warning ("pending current providers");
provider_list_free (parser.current_providers);
}
g_free (parser.current_country);
g_free (parser.text_buffer);
out:
return parser.table;
}
static void
dump_generic (ShellMobileAccessMethod *method)
{
GSList *iter;
GString *dns;
g_print (" username: %s\n", method->username ? method->username : "");
g_print (" password: %s\n", method->password ? method->password : "");
dns = g_string_new (NULL);
for (iter = method->dns; iter; iter = g_slist_next (iter))
g_string_append_printf (dns, "%s%s", dns->len ? ", " : "", (char *) iter->data);
g_print (" dns : %s\n", dns->str);
g_string_free (dns, TRUE);
g_print (" gateway : %s\n", method->gateway ? method->gateway : "");
}
static void
dump_cdma (ShellMobileAccessMethod *method)
{
g_print (" CDMA: %s\n", method->name);
dump_generic (method);
}
static void
dump_gsm (ShellMobileAccessMethod *method)
{
g_print (" APN: %s (%s)\n", method->name, method->gsm_apn);
dump_generic (method);
}
static void
dump_country (gpointer key, gpointer value, gpointer user_data)
{
GSList *miter, *citer;
ShellCountryMobileProvider *country_provider = value;
g_print ("Country: %s (%s)\n",
country_provider->country_code,
country_provider->country_name);
for (citer = country_provider->providers; citer; citer = g_slist_next (citer)) {
ShellMobileProvider *provider = citer->data;
g_print (" Provider: %s (%s)\n", provider->name, (const char *) key);
for (miter = provider->methods; miter; miter = g_slist_next (miter)) {
ShellMobileAccessMethod *method = miter->data;
GSList *liter;
for (liter = provider->gsm_mcc_mnc; liter; liter = g_slist_next (liter)) {
ShellGsmMccMnc *m = liter->data;
g_print (" MCC/MNC: %s-%s\n", m->mcc, m->mnc);
}
for (liter = provider->cdma_sid; liter; liter = g_slist_next (liter))
g_print (" SID: %d\n", GPOINTER_TO_UINT (liter->data));
switch (method->type) {
case SHELL_MOBILE_ACCESS_METHOD_TYPE_CDMA:
dump_cdma (method);
break;
case SHELL_MOBILE_ACCESS_METHOD_TYPE_GSM:
dump_gsm (method);
break;
default:
break;
}
g_print ("\n");
}
}
}
void
shell_mobile_providers_dump (GHashTable *country_providers)
{
g_return_if_fail (country_providers != NULL);
g_hash_table_foreach (country_providers, dump_country, NULL);
}
/* All the following don't exist in nm-applet, because C doesn't need
those. They're only needed for the introspection annotations
*/
/**
* shell_mobile_provider_get_gsm_mcc_mnc:
* @provider: a #ShellMobileProvider
*
* Returns: (element-type Shell.GsmMccMnc) (transfer none): the
* list of #ShellGsmMccMnc this provider exposes
*/
GSList *
shell_mobile_provider_get_gsm_mcc_mnc (ShellMobileProvider *provider)
{
return provider->gsm_mcc_mnc;
}
/**
* shell_mobile_provider_get_cdma_sid:
* @provider: a #ShellMobileProvider
*
* Returns: (element-type guint32) (transfer none): the
* list of CDMA sids this provider exposes
*/
GSList *
shell_mobile_provider_get_cdma_sid (ShellMobileProvider *provider)
{
return provider->cdma_sid;
}

View File

@ -1,111 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* Copyright (C) 2009 Novell, Inc.
* Author: Tambet Ingo (tambet@gmail.com).
*
* Copyright (C) 2009 - 2010 Red Hat, Inc.
*
* Ported to GNOME Shell by Giovanni Campagna <scampa.giovanni@gmail.com>
* Porting consisted only in replacing nmn with shell, to be compatible with
* GObject Introspection namespacing
*/
#ifndef SHELL_MOBILE_PROVIDERS_H
#define SHELL_MOBILE_PROVIDERS_H
#include <glib.h>
#include <glib-object.h>
#define SHELL_TYPE_MOBILE_PROVIDER (shell_mobile_provider_get_type ())
#define SHELL_TYPE_MOBILE_ACCESS_METHOD (shell_mobile_access_method_get_type ())
typedef enum {
SHELL_MOBILE_ACCESS_METHOD_TYPE_UNKNOWN = 0,
SHELL_MOBILE_ACCESS_METHOD_TYPE_GSM,
SHELL_MOBILE_ACCESS_METHOD_TYPE_CDMA
} ShellMobileAccessMethodType;
typedef struct {
char *mcc;
char *mnc;
} ShellGsmMccMnc;
typedef struct {
char *name;
/* maps lang (char *) -> name (char *) */
GHashTable *lcl_names;
char *username;
char *password;
char *gateway;
GSList *dns; /* GSList of 'char *' */
/* Only used with SHELL_PROVIDER_TYPE_GSM */
char *gsm_apn;
ShellMobileAccessMethodType type;
gint refs;
} ShellMobileAccessMethod;
typedef struct {
char *name;
/* maps lang (char *) -> name (char *) */
GHashTable *lcl_names;
GSList *methods; /* GSList of ShellMobileAccessMethod */
GSList *gsm_mcc_mnc; /* GSList of ShellGsmMccMnc */
GSList *cdma_sid; /* GSList of guint32 */
gint refs;
} ShellMobileProvider;
typedef struct {
char *country_code;
char *country_name;
GSList *providers;
gint refs;
} ShellCountryMobileProvider;
GType shell_gsm_mcc_mnc_get_type (void); /* added in porting */
GType shell_mobile_access_method_get_type (void);
GType shell_mobile_provider_get_type (void);
GType shell_country_mobile_provider_get_type (void);
ShellMobileProvider *shell_mobile_provider_ref (ShellMobileProvider *provider);
void shell_mobile_provider_unref (ShellMobileProvider *provider);
GSList * shell_mobile_provider_get_gsm_mcc_mnc (ShellMobileProvider *provider);
GSList * shell_mobile_provider_get_cdma_sid (ShellMobileProvider *provider);
ShellMobileAccessMethod *shell_mobile_access_method_ref (ShellMobileAccessMethod *method);
void shell_mobile_access_method_unref (ShellMobileAccessMethod *method);
ShellCountryMobileProvider *shell_country_mobile_provider_ref (ShellCountryMobileProvider *country_provider);
void shell_country_mobile_provider_unref (ShellCountryMobileProvider *country_provider);
const gchar *shell_country_mobile_provider_get_country_code (ShellCountryMobileProvider *country_provider);
const gchar *shell_country_mobile_provider_get_country_name (ShellCountryMobileProvider *country_provider);
GSList *shell_country_mobile_provider_get_providers (ShellCountryMobileProvider *country_provider);
GHashTable *shell_mobile_providers_parse (const gchar *country_codes,
const gchar *service_providers);
void shell_mobile_providers_dump (GHashTable *country_providers);
#endif /* SHELL_MOBILE_PROVIDERS_H */

View File

@ -26,14 +26,11 @@ TEST_JS = \
testcommon/border-image.png \ testcommon/border-image.png \
testcommon/face-plain.png \ testcommon/face-plain.png \
testcommon/ui.js \ testcommon/ui.js \
testcommon/iso3166-test.tab \
testcommon/serviceproviders-test.xml \
unit/format.js \ unit/format.js \
unit/insertSorted.js \ unit/insertSorted.js \
unit/markup.js \ unit/markup.js \
unit/jsParse.js \ unit/jsParse.js \
unit/url.js \ unit/url.js
unit/mobileProviders.js
EXTRA_DIST += $(TEST_JS) EXTRA_DIST += $(TEST_JS)
TEST_MISC = \ TEST_MISC = \

View File

@ -1,3 +0,0 @@
# Test country list
ES Spain
US United States

View File

@ -1,44 +0,0 @@
<?xml version="1.0"?>
<!-- -*- Mode: XML; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- -->
<!DOCTYPE serviceproviders SYSTEM "serviceproviders.2.dtd">
<serviceproviders format="2.0">
<!-- United States -->
<country code="us">
<provider>
<name>AT&amp;T</name>
<gsm>
<network-id mcc="310" mnc="038"/>
<network-id mcc="310" mnc="090"/>
<network-id mcc="310" mnc="150"/>
</gsm>
</provider>
<provider>
<name>Verizon</name>
<gsm>
<network-id mcc="310" mnc="995"/>
<network-id mcc="311" mnc="480"/>
</gsm>
<cdma>
<sid value="2"/>
<sid value="4"/>
<sid value="5"/>
</cdma>
</provider>
</country>
<!-- Spain -->
<country code="es">
<provider>
<name>Movistar (Telefónica)</name>
<gsm>
<network-id mcc="214" mnc="05"/>
<network-id mcc="214" mnc="07"/>
</gsm>
</provider>
</country>
</serviceproviders>

View File

@ -1,78 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const GLib = imports.gi.GLib;
const Shell = imports.gi.Shell;
const JsUnit = imports.jsUnit;
const ModemManager = imports.misc.modemManager;
const Environment = imports.ui.environment;
Environment.init();
// Load test providers table
let countrycodesPath = GLib.getenv("GNOME_SHELL_TESTSDIR") + "/testcommon/iso3166-test.tab";
let serviceprovidersPath = GLib.getenv("GNOME_SHELL_TESTSDIR") + "/testcommon/serviceproviders-test.xml";
let providersTable = Shell.mobile_providers_parse(countrycodesPath, serviceprovidersPath);
function assertCountryFound(country_code, expected_country_name) {
let country = providersTable[country_code];
JsUnit.assertNotUndefined(country);
JsUnit.assertEquals(country.get_country_name(), expected_country_name);
}
function assertCountryNotFound(country_code) {
let country = providersTable[country_code];
JsUnit.assertUndefined(country);
}
function assertProviderFoundForMCCMNC(mccmnc, expected_provider_name) {
let provider_name = ModemManager.findProviderForMCCMNC(providersTable, mccmnc);
JsUnit.assertEquals(provider_name, expected_provider_name);
}
function assertProviderNotFoundForMCCMNC(mccmnc) {
let provider_name = ModemManager.findProviderForMCCMNC(providersTable, mccmnc);
JsUnit.assertNull(provider_name);
}
function assertProviderFoundForSid(sid, expected_provider_name) {
let provider_name = ModemManager.findProviderForSid(providersTable, sid);
JsUnit.assertEquals(provider_name, expected_provider_name);
}
function assertProviderNotFoundForSid(sid) {
let provider_name = ModemManager.findProviderForSid(providersTable, sid);
JsUnit.assertNull(provider_name);
}
// TEST:
// * Both 'US' and 'ES' country info should be loaded
assertCountryFound("ES", "Spain");
assertCountryFound("US", "United States");
// TEST:
// * Country info for 'FR' not given
assertCountryNotFound("FR");
// TEST:
// * Ensure operator names are found for the given MCC/MNC codes
assertProviderFoundForMCCMNC("21405", "Movistar (Telefónica)");
assertProviderFoundForMCCMNC("21407", "Movistar (Telefónica)");
assertProviderFoundForMCCMNC("310038", "AT&T");
assertProviderFoundForMCCMNC("310090", "AT&T");
assertProviderFoundForMCCMNC("310150", "AT&T");
assertProviderFoundForMCCMNC("310995", "Verizon");
assertProviderFoundForMCCMNC("311480", "Verizon");
// TEST:
// * Ensure NULL is given for unexpected MCC/MNC codes
assertProviderNotFoundForMCCMNC("12345");
// TEST:
// * Ensure operator names are found for the given SID codes
assertProviderFoundForSid(2, "Verizon");
assertProviderFoundForSid(4, "Verizon");
assertProviderFoundForSid(5, "Verizon");
// TEST:
// * Ensure NULL is given for unexpected SID codes
assertProviderNotFoundForSid(1);