aboutsummaryrefslogtreecommitdiff
path: root/src/mm-modem-helpers.c
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@lanedo.com>2011-11-30 13:29:00 +0100
committerAleksander Morgado <aleksander@lanedo.com>2012-03-15 14:14:30 +0100
commita92e9c59c1c2a4b2078e02d631b04eced68320be (patch)
treeb3cb815289adb68b171eccff6a6d455d42ad163b /src/mm-modem-helpers.c
parenta265798e0d4cf016417c85b7b8cfd288a493148f (diff)
modem-helpers: provide list of scanned networks in a list of structs
We provide the result of the +COPS=? parsing in a GList of MM3gppNetworkInfo structures. We avoid the previous hash table, or using a dictionary, as a list of structs with a predefined set of elements, which should be easier for plugins wanting to make their own version
Diffstat (limited to 'src/mm-modem-helpers.c')
-rw-r--r--src/mm-modem-helpers.c175
1 files changed, 116 insertions, 59 deletions
diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c
index d046e89e..63bc07dd 100644
--- a/src/mm-modem-helpers.c
+++ b/src/mm-modem-helpers.c
@@ -25,6 +25,7 @@
#include <ModemManager.h>
#include <mm-errors-types.h>
+#include <mm-enums-types.h>
#include "mm-modem-helpers.h"
#include "mm-log.h"
@@ -46,10 +47,20 @@ mm_strip_tag (const char *str, const char *cmd)
/*************************************************************************/
static void
-save_scan_value (GHashTable *hash, const char *key, GMatchInfo *info, guint32 num)
+mm_3gpp_network_info_free (MM3gppNetworkInfo *info)
{
- char *quoted;
- size_t len;
+ g_free (info->operator_long);
+ g_free (info->operator_short);
+ g_free (info->operator_code);
+ g_free (info);
+}
+
+void
+mm_3gpp_network_info_list_free (GList *info_list)
+{
+ g_list_foreach (info_list, (GFunc)mm_3gpp_network_info_free, NULL);
+ g_list_free (info_list);
+}
static MMModemAccessTech
get_mm_access_tech_from_etsi_access_tech (guint act)
@@ -77,11 +88,15 @@ get_mm_access_tech_from_etsi_access_tech (guint act)
}
}
- g_return_if_fail (info != NULL);
+static gchar *
+get_unquoted_scan_value (GMatchInfo *info, guint32 num)
+{
+ gchar *quoted;
+ gsize len;
quoted = g_match_info_fetch (info, num);
if (!quoted)
- return;
+ return NULL;
len = strlen (quoted);
@@ -94,24 +109,53 @@ get_mm_access_tech_from_etsi_access_tech (guint act)
if (!strlen (quoted)) {
g_free (quoted);
- return;
+ return NULL;
}
- g_hash_table_insert (hash, g_strdup (key), quoted);
+ return quoted;
}
-/* If the response was successfully parsed (even if no valid entries were
- * found) the pointer array will be returned.
- */
-GPtrArray *
-mm_gsm_parse_scan_response (const char *reply, GError **error)
+static MMModem3gppNetworkAvailability
+parse_network_status (const gchar *str)
+{
+ /* Expecting a value between '0' and '3' inclusive */
+ if (!str ||
+ strlen (str) != 1 ||
+ str[0] < '0' ||
+ str[0] > '3') {
+ mm_warn ("Cannot parse network status: '%s'", str);
+ return MM_MODEM_3GPP_NETWORK_AVAILABILITY_UNKNOWN;
+ }
+
+ return (MMModem3gppNetworkAvailability) (str[0] - '0');
+}
+
+static MMModemAccessTech
+parse_access_tech (const gchar *str)
+{
+ /* Recognized access technologies are between '0' and '7' inclusive... */
+ if (!str ||
+ strlen (str) != 1 ||
+ str[0] < '0' ||
+ str[0] > '7') {
+ mm_warn ("Cannot parse access tech: '%s'", str);
+ return MM_MODEM_ACCESS_TECH_UNKNOWN;
+ }
+
+ return get_mm_access_tech_from_etsi_access_tech (str[0] - '0');
+}
+
+GList *
+mm_3gpp_parse_scan_response (const gchar *reply,
+ GError **error)
{
- /* Got valid reply */
- GPtrArray *results = NULL;
GRegex *r;
+ GList *info_list = NULL;
GMatchInfo *match_info;
- GError *err = NULL;
gboolean umts_format = TRUE;
+ GEnumClass *network_availability_class;
+ GEnumClass *access_tech_class;
+ GError *inner_error = NULL;
g_return_val_if_fail (reply != NULL, NULL);
if (error)
@@ -140,13 +184,13 @@ mm_gsm_parse_scan_response (const char *reply, GError **error)
* +COPS: (2,"","T-Mobile","31026",0),(1,"AT&T","AT&T","310410"),0)
*/
- r = g_regex_new ("\\((\\d),([^,\\)]*),([^,\\)]*),([^,\\)]*)[\\)]?,(\\d)\\)", G_REGEX_UNGREEDY, 0, &err);
- if (err) {
- mm_err ("Invalid regular expression: %s", err->message);
- g_error_free (err);
+ r = g_regex_new ("\\((\\d),([^,\\)]*),([^,\\)]*),([^,\\)]*)[\\)]?,(\\d)\\)", G_REGEX_UNGREEDY, 0, &inner_error);
+ if (inner_error) {
+ mm_err ("Invalid regular expression: %s", inner_error->message);
+ g_error_free (inner_error);
g_set_error_literal (error,
MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
- "Could not parse scan results.");
+ "Could not parse scan results");
return NULL;
}
@@ -169,13 +213,13 @@ mm_gsm_parse_scan_response (const char *reply, GError **error)
* +COPS: (2,"T - Mobile",,"31026"),(1,"Einstein PCS",,"31064"),(1,"Cingular",,"31041"),,(0,1,3),(0,2)
*/
- r = g_regex_new ("\\((\\d),([^,\\)]*),([^,\\)]*),([^\\)]*)\\)", G_REGEX_UNGREEDY, 0, &err);
- if (err) {
- mm_err ("Invalid regular expression: %s", err->message);
- g_error_free (err);
+ r = g_regex_new ("\\((\\d),([^,\\)]*),([^,\\)]*),([^\\)]*)\\)", G_REGEX_UNGREEDY, 0, &inner_error);
+ if (inner_error) {
+ mm_err ("Invalid regular expression: %s", inner_error->message);
+ g_error_free (inner_error);
g_set_error_literal (error,
MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
- "Could not parse scan results.");
+ "Could not parse scan results");
return NULL;
}
@@ -183,39 +227,43 @@ mm_gsm_parse_scan_response (const char *reply, GError **error)
umts_format = FALSE;
}
+ network_availability_class = G_ENUM_CLASS (g_type_class_ref (MM_TYPE_MODEM_3GPP_NETWORK_AVAILABILITY));
+ access_tech_class = G_ENUM_CLASS (g_type_class_ref (MM_TYPE_MODEM_ACCESS_TECH));
+
/* Parse the results */
- results = g_ptr_array_new ();
while (g_match_info_matches (match_info)) {
- GHashTable *hash;
- char *access_tech = NULL;
- const char *tmp;
+ MM3gppNetworkInfo *info;
+ gchar *tmp;
gboolean valid = FALSE;
- hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+ info = g_new0 (MM3gppNetworkInfo, 1);
+
+ tmp = get_unquoted_scan_value (match_info, 1);
+ info->status = parse_network_status (tmp);
+ g_free (tmp);
- save_scan_value (hash, MM_SCAN_TAG_STATUS, match_info, 1);
- save_scan_value (hash, MM_SCAN_TAG_OPER_LONG, match_info, 2);
- save_scan_value (hash, MM_SCAN_TAG_OPER_SHORT, match_info, 3);
- save_scan_value (hash, MM_SCAN_TAG_OPER_NUM, match_info, 4);
+ info->operator_long = get_unquoted_scan_value (match_info, 2);
+ info->operator_short = get_unquoted_scan_value (match_info, 3);
+ info->operator_code = get_unquoted_scan_value (match_info, 4);
- /* Only try for access technology with UMTS-format matches */
- if (umts_format)
- access_tech = g_match_info_fetch (match_info, 5);
- if (access_tech && (strlen (access_tech) == 1)) {
- /* Recognized access technologies are between '0' and '6' inclusive... */
- if ((access_tech[0] >= '0') && (access_tech[0] <= '6'))
- g_hash_table_insert (hash, g_strdup (MM_SCAN_TAG_ACCESS_TECH), access_tech);
- } else
- g_free (access_tech);
+ /* Only try for access technology with UMTS-format matches.
+ * If none give, assume GSM */
+ tmp = (umts_format ?
+ get_unquoted_scan_value (match_info, 5) :
+ NULL);
+ info->access_tech = (tmp ?
+ parse_access_tech (tmp) :
+ MM_MODEM_ACCESS_TECH_GSM);
+ g_free (tmp);
/* If the operator number isn't valid (ie, at least 5 digits),
* ignore the scan result; it's probably the parameter stuff at the
* end of the +COPS response. The regex will sometimes catch this
* but there's no good way to ignore it.
*/
- tmp = g_hash_table_lookup (hash, MM_SCAN_TAG_OPER_NUM);
- if (tmp && (strlen (tmp) >= 5)) {
+ if (info->operator_code && (strlen (info->operator_code) >= 5)) {
valid = TRUE;
+ tmp = info->operator_code;
while (*tmp) {
if (!isdigit (*tmp) && (*tmp != '-')) {
valid = FALSE;
@@ -223,13 +271,28 @@ mm_gsm_parse_scan_response (const char *reply, GError **error)
}
tmp++;
}
-
- if (valid)
- g_ptr_array_add (results, hash);
}
- if (!valid)
- g_hash_table_destroy (hash);
+ if (valid) {
+ GEnumValue *network_availability;
+ GEnumValue *access_tech;
+
+ network_availability = g_enum_get_value (network_availability_class,
+ info->status);
+ access_tech = g_enum_get_value (access_tech_class,
+ info->access_tech);
+
+ mm_dbg ("Found network '%s' ('%s','%s'); availability: %s, access tech: %s",
+ info->operator_code,
+ info->operator_short ? info->operator_short : "no short name",
+ info->operator_long ? info->operator_long : "no long name",
+ network_availability->value_nick,
+ access_tech->value_nick);
+
+ info_list = g_list_prepend (info_list, info);
+ }
+ else
+ mm_3gpp_network_info_free (info);
g_match_info_next (match_info, NULL);
}
@@ -237,16 +300,10 @@ mm_gsm_parse_scan_response (const char *reply, GError **error)
g_match_info_free (match_info);
g_regex_unref (r);
- return results;
-}
-
-void
-mm_gsm_destroy_scan_data (gpointer data)
-{
- GPtrArray *results = (GPtrArray *) data;
+ g_type_class_unref (network_availability_class);
+ g_type_class_unref (access_tech_class);
- g_ptr_array_foreach (results, (GFunc) g_hash_table_destroy, NULL);
- g_ptr_array_free (results, TRUE);
+ return info_list;
}
/*************************************************************************/