diff options
author | Aleksander Morgado <aleksander@lanedo.com> | 2011-11-30 13:29:00 +0100 |
---|---|---|
committer | Aleksander Morgado <aleksander@lanedo.com> | 2012-03-15 14:14:30 +0100 |
commit | a92e9c59c1c2a4b2078e02d631b04eced68320be (patch) | |
tree | b3cb815289adb68b171eccff6a6d455d42ad163b /src/mm-modem-helpers.c | |
parent | a265798e0d4cf016417c85b7b8cfd288a493148f (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.c | 175 |
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; } /*************************************************************************/ |