diff options
author | Aleksander Morgado <aleksander@lanedo.com> | 2012-03-06 14:15:43 +0100 |
---|---|---|
committer | Aleksander Morgado <aleksander@lanedo.com> | 2012-03-16 14:53:21 +0100 |
commit | 1f250585dd810e8b6db2514036a470ab955febf4 (patch) | |
tree | eaedab739d1a2eb5b7ddcddc3203bd2054e2f3e9 /src/mm-modem-helpers.c | |
parent | c824ee310603971ed4ccbfb9531b83dcfcc75bd6 (diff) |
modem-helpers: refactor and reorganize sources
Diffstat (limited to 'src/mm-modem-helpers.c')
-rw-r--r-- | src/mm-modem-helpers.c | 1768 |
1 files changed, 897 insertions, 871 deletions
diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c index 9e875a62..9a4a37ae 100644 --- a/src/mm-modem-helpers.c +++ b/src/mm-modem-helpers.c @@ -11,7 +11,8 @@ * GNU General Public License for more details: * * Copyright (C) 2008 - 2009 Novell, Inc. - * Copyright (C) 2009 - 2011 Red Hat, Inc. + * Copyright (C) 2009 - 2012 Red Hat, Inc. + * Copyright (C) 2012 Google, Inc. */ #include <config.h> @@ -29,10 +30,12 @@ #include "mm-modem-helpers.h" #include "mm-log.h" -const char * -mm_strip_tag (const char *str, const char *cmd) +/*****************************************************************************/ + +const gchar * +mm_strip_tag (const gchar *str, const gchar *cmd) { - const char *p = str; + const gchar *p = str; if (p) { if (!strncmp (p, cmd, strlen (cmd))) @@ -40,9 +43,237 @@ mm_strip_tag (const char *str, const char *cmd) while (isspace (*p)) p++; } + return p; } +/*****************************************************************************/ + +guint +mm_count_bits_set (gulong number) +{ + guint c; + + for (c = 0; number; c++) + number &= number - 1; + return c; +} + +/*****************************************************************************/ + +gchar * +mm_create_device_identifier (guint vid, + guint pid, + const gchar *ati, + const gchar *ati1, + const gchar *gsn, + const gchar *revision, + const gchar *model, + const gchar *manf) +{ + GString *devid, *msg = NULL; + GChecksum *sum; + gchar *p, *ret = NULL; + gchar str_vid[10], str_pid[10]; + + /* Build up the device identifier */ + devid = g_string_sized_new (50); + if (ati) + g_string_append (devid, ati); + if (ati1) { + /* Only append "ATI1" if it's differnet than "ATI" */ + if (!ati || (strcmp (ati, ati1) != 0)) + g_string_append (devid, ati1); + } + if (gsn) + g_string_append (devid, gsn); + if (revision) + g_string_append (devid, revision); + if (model) + g_string_append (devid, model); + if (manf) + g_string_append (devid, manf); + + if (!strlen (devid->str)) { + g_string_free (devid, TRUE); + return NULL; + } + + p = devid->str; + msg = g_string_sized_new (strlen (devid->str) + 17); + + sum = g_checksum_new (G_CHECKSUM_SHA1); + + if (vid) { + snprintf (str_vid, sizeof (str_vid) - 1, "%08x", vid); + g_checksum_update (sum, (const guchar *) &str_vid[0], strlen (str_vid)); + g_string_append_printf (msg, "%08x", vid); + } + if (vid) { + snprintf (str_pid, sizeof (str_pid) - 1, "%08x", pid); + g_checksum_update (sum, (const guchar *) &str_pid[0], strlen (str_pid)); + g_string_append_printf (msg, "%08x", pid); + } + + while (*p) { + /* Strip spaces and linebreaks */ + if (!isblank (*p) && !isspace (*p) && isascii (*p)) { + g_checksum_update (sum, (const guchar *) p, 1); + g_string_append_c (msg, *p); + } + p++; + } + ret = g_strdup (g_checksum_get_string (sum)); + g_checksum_free (sum); + + mm_dbg ("Device ID source '%s'", msg->str); + mm_dbg ("Device ID '%s'", ret); + g_string_free (msg, TRUE); + g_string_free (devid, TRUE); + + return ret; +} + +/*****************************************************************************/ + +/* +CREG: <stat> (GSM 07.07 CREG=1 unsolicited) */ +#define CREG1 "\\+(CREG|CGREG):\\s*0*([0-9])" + +/* +CREG: <n>,<stat> (GSM 07.07 CREG=1 solicited) */ +#define CREG2 "\\+(CREG|CGREG):\\s*0*([0-9]),\\s*0*([0-9])" + +/* +CREG: <stat>,<lac>,<ci> (GSM 07.07 CREG=2 unsolicited) */ +#define CREG3 "\\+(CREG|CGREG):\\s*0*([0-9]),\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)" + +/* +CREG: <n>,<stat>,<lac>,<ci> (GSM 07.07 solicited and some CREG=2 unsolicited) */ +#define CREG4 "\\+(CREG|CGREG):\\s*0*([0-9]),\\s*0*([0-9])\\s*,\\s*([^,]*)\\s*,\\s*([^,\\s]*)" + +/* +CREG: <stat>,<lac>,<ci>,<AcT> (ETSI 27.007 CREG=2 unsolicited) */ +#define CREG5 "\\+(CREG|CGREG):\\s*0*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*0*([0-9])" + +/* +CREG: <n>,<stat>,<lac>,<ci>,<AcT> (ETSI 27.007 solicited and some CREG=2 unsolicited) */ +#define CREG6 "\\+(CREG|CGREG):\\s*0*([0-9]),\\s*0*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*0*([0-9])" + +/* +CREG: <n>,<stat>,<lac>,<ci>,<AcT?>,<something> (Samsung Wave S8500) */ +/* '<CR><LF>+CREG: 2,1,000B,2816, B, C2816<CR><LF><CR><LF>OK<CR><LF>' */ +#define CREG7 "\\+(CREG|CGREG):\\s*0*([0-9]),\\s*0*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*[^,\\s]*" + +/* +CREG: <stat>,<lac>,<ci>,<AcT>,<RAC> (ETSI 27.007 v9.20 CREG=2 unsolicited with RAC) */ +#define CREG8 "\\+(CREG|CGREG):\\s*0*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*0*([0-9])\\s*,\\s*([^,\\s]*)" + +GPtrArray * +mm_3gpp_creg_regex_get (gboolean solicited) +{ + GPtrArray *array = g_ptr_array_sized_new (7); + GRegex *regex; + + /* #1 */ + if (solicited) + regex = g_regex_new (CREG1 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + else + regex = g_regex_new ("\\r\\n" CREG1 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + g_assert (regex); + g_ptr_array_add (array, regex); + + /* #2 */ + if (solicited) + regex = g_regex_new (CREG2 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + else + regex = g_regex_new ("\\r\\n" CREG2 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + g_assert (regex); + g_ptr_array_add (array, regex); + + /* #3 */ + if (solicited) + regex = g_regex_new (CREG3 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + else + regex = g_regex_new ("\\r\\n" CREG3 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + g_assert (regex); + g_ptr_array_add (array, regex); + + /* #4 */ + if (solicited) + regex = g_regex_new (CREG4 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + else + regex = g_regex_new ("\\r\\n" CREG4 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + g_assert (regex); + g_ptr_array_add (array, regex); + + /* #5 */ + if (solicited) + regex = g_regex_new (CREG5 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + else + regex = g_regex_new ("\\r\\n" CREG5 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + g_assert (regex); + g_ptr_array_add (array, regex); + + /* #6 */ + if (solicited) + regex = g_regex_new (CREG6 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + else + regex = g_regex_new ("\\r\\n" CREG6 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + g_assert (regex); + g_ptr_array_add (array, regex); + + /* #7 */ + if (solicited) + regex = g_regex_new (CREG7 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + else + regex = g_regex_new ("\\r\\n" CREG7 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + g_assert (regex); + g_ptr_array_add (array, regex); + + /* #8 */ + if (solicited) + regex = g_regex_new (CREG8 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + else + regex = g_regex_new ("\\r\\n" CREG8 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + g_assert (regex); + g_ptr_array_add (array, regex); + + return array; +} + +void +mm_3gpp_creg_regex_destroy (GPtrArray *array) +{ + g_ptr_array_foreach (array, (GFunc) g_regex_unref, NULL); + g_ptr_array_free (array, TRUE); +} + +/*************************************************************************/ + +GRegex * +mm_3gpp_ciev_regex_get (void) +{ + return g_regex_new ("\\r\\n\\+CIEV: (.*),(\\d)\\r\\n", + G_REGEX_RAW | G_REGEX_OPTIMIZE, + 0, + NULL); +} + +/*************************************************************************/ + +GRegex * +mm_3gpp_cusd_regex_get (void) +{ + return g_regex_new ("\\r\\n\\+CUSD:\\s*(.*)\\r\\n", + G_REGEX_RAW | G_REGEX_OPTIMIZE, + 0, + NULL); +} + +/*************************************************************************/ + +GRegex * +mm_3gpp_cmti_regex_get (void) +{ + return g_regex_new ("\\r\\n\\+CMTI: \"(\\S+)\",(\\d+)\\r\\n", + G_REGEX_RAW | G_REGEX_OPTIMIZE, + 0, + NULL); +} + /*************************************************************************/ static void @@ -144,8 +375,8 @@ parse_access_tech (const gchar *str) } GList * -mm_3gpp_parse_scan_response (const gchar *reply, - GError **error) +mm_3gpp_parse_cops_test_response (const gchar *reply, + GError **error) { GRegex *r; GList *info_list = NULL; @@ -294,155 +525,6 @@ mm_3gpp_parse_scan_response (const gchar *reply, /*************************************************************************/ -static MMSmsStorage -storage_from_str (const gchar *str) -{ - if (g_str_equal (str, "SM")) - return MM_SMS_STORAGE_SM; - if (g_str_equal (str, "ME")) - return MM_SMS_STORAGE_ME; - if (g_str_equal (str, "MT")) - return MM_SMS_STORAGE_MT; - if (g_str_equal (str, "SR")) - return MM_SMS_STORAGE_SR; - if (g_str_equal (str, "BM")) - return MM_SMS_STORAGE_BM; - if (g_str_equal (str, "TA")) - return MM_SMS_STORAGE_TA; - return MM_SMS_STORAGE_UNKNOWN; -} - -gboolean -mm_3gpp_parse_cpms_format_response (const gchar *reply, - GArray **mem1, - GArray **mem2, - GArray **mem3) -{ - GRegex *r; - gchar **split; - guint i; - - g_assert (mem1 != NULL); - g_assert (mem2 != NULL); - g_assert (mem3 != NULL); - - /* - * +CPMS: ("SM","ME"),("SM","ME"),("SM","ME") - */ - split = g_strsplit_set (mm_strip_tag (reply, "+CPMS:"), "()", -1); - if (!split) - return FALSE; - - r = g_regex_new ("\\s*\"([^,\\)]+)\"\\s*", 0, 0, NULL); - g_assert (r); - - for (i = 0; split[i]; i++) { - GMatchInfo *match_info; - - /* Got a range group to match */ - if (g_regex_match_full (r, split[i], strlen (split[i]), 0, 0, &match_info, NULL)) { - GArray *array = NULL; - - while (g_match_info_matches (match_info)) { - gchar *str; - - str = g_match_info_fetch (match_info, 1); - if (str) { - MMSmsStorage storage; - - if (!array) - array = g_array_new (FALSE, FALSE, sizeof (MMSmsStorage)); - - storage = storage_from_str (str); - g_array_append_val (array, storage); - g_free (str); - } - - g_match_info_next (match_info, NULL); - } - - if (!*mem1) - *mem1 = array; - else if (!*mem2) - *mem2 = array; - else if (!*mem3) - *mem3 = array; - } - g_match_info_free (match_info); - - if (*mem3 != NULL) - break; /* once we got the last group, exit... */ - } - - g_strfreev (split); - g_regex_unref (r); - - g_warn_if_fail (*mem1 != NULL); - g_warn_if_fail (*mem2 != NULL); - g_warn_if_fail (*mem3 != NULL); - - return (*mem1 && *mem2 && *mem3); -} - -/*************************************************************************/ - -#define CMGF_TAG "+CMGF:" - -gboolean -mm_3gpp_parse_cmgf_format_response (const gchar *reply, - gboolean *sms_pdu_supported, - gboolean *sms_text_supported, - GError **error) -{ - GRegex *r; - GMatchInfo *match_info; - char *s; - guint32 min = -1, max = -1; - - /* Strip whitespace and response tag */ - if (g_str_has_prefix (reply, CMGF_TAG)) - reply += strlen (CMGF_TAG); - while (isspace (*reply)) - reply++; - - r = g_regex_new ("\\(?\\s*(\\d+)\\s*[-,]?\\s*(\\d+)?\\s*\\)?", 0, 0, error); - if (!r) - return FALSE; - - if (!g_regex_match_full (r, reply, strlen (reply), 0, 0, &match_info, NULL)) { - g_set_error (error, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Failed to parse CMGF query result '%s'", - reply); - g_match_info_free (match_info); - g_regex_unref (r); - return FALSE; - } - - s = g_match_info_fetch (match_info, 1); - if (s) - min = atoi (s); - g_free (s); - - s = g_match_info_fetch (match_info, 2); - if (s) - max = atoi (s); - g_free (s); - - /* CMGF=0 for PDU mode */ - *sms_pdu_supported = (min == 0); - - /* CMGF=1 for Text mode */ - *sms_text_supported = (max >= 1); - - g_match_info_free (match_info); - g_regex_unref (r); - return TRUE; -} - -/*************************************************************************/ - static void mm_3gpp_pdp_context_free (MM3gppPdpContext *pdp) { @@ -465,8 +547,8 @@ mm_3gpp_pdp_context_cmp (MM3gppPdpContext *a, } GList * -mm_3gpp_parse_pdp_query_response (const gchar *reply, - GError **error) +mm_3gpp_parse_cgdcont_read_response (const gchar *reply, + GError **error) { GError *inner_error = NULL; GRegex *r; @@ -519,151 +601,11 @@ mm_3gpp_parse_pdp_query_response (const gchar *reply, /*************************************************************************/ -/* +CREG: <stat> (GSM 07.07 CREG=1 unsolicited) */ -#define CREG1 "\\+(CREG|CGREG):\\s*0*([0-9])" - -/* +CREG: <n>,<stat> (GSM 07.07 CREG=1 solicited) */ -#define CREG2 "\\+(CREG|CGREG):\\s*0*([0-9]),\\s*0*([0-9])" - -/* +CREG: <stat>,<lac>,<ci> (GSM 07.07 CREG=2 unsolicited) */ -#define CREG3 "\\+(CREG|CGREG):\\s*0*([0-9]),\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)" - -/* +CREG: <n>,<stat>,<lac>,<ci> (GSM 07.07 solicited and some CREG=2 unsolicited) */ -#define CREG4 "\\+(CREG|CGREG):\\s*0*([0-9]),\\s*0*([0-9])\\s*,\\s*([^,]*)\\s*,\\s*([^,\\s]*)" - -/* +CREG: <stat>,<lac>,<ci>,<AcT> (ETSI 27.007 CREG=2 unsolicited) */ -#define CREG5 "\\+(CREG|CGREG):\\s*0*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*0*([0-9])" - -/* +CREG: <n>,<stat>,<lac>,<ci>,<AcT> (ETSI 27.007 solicited and some CREG=2 unsolicited) */ -#define CREG6 "\\+(CREG|CGREG):\\s*0*([0-9]),\\s*0*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*0*([0-9])" - -/* +CREG: <n>,<stat>,<lac>,<ci>,<AcT?>,<something> (Samsung Wave S8500) */ -/* '<CR><LF>+CREG: 2,1,000B,2816, B, C2816<CR><LF><CR><LF>OK<CR><LF>' */ -#define CREG7 "\\+(CREG|CGREG):\\s*0*([0-9]),\\s*0*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*[^,\\s]*" - -/* +CREG: <stat>,<lac>,<ci>,<AcT>,<RAC> (ETSI 27.007 v9.20 CREG=2 unsolicited with RAC) */ -#define CREG8 "\\+(CREG|CGREG):\\s*0*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*0*([0-9])\\s*,\\s*([^,\\s]*)" - -GPtrArray * -mm_3gpp_creg_regex_get (gboolean solicited) -{ - GPtrArray *array = g_ptr_array_sized_new (7); - GRegex *regex; - - /* #1 */ - if (solicited) - regex = g_regex_new (CREG1 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - else - regex = g_regex_new ("\\r\\n" CREG1 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - g_assert (regex); - g_ptr_array_add (array, regex); - - /* #2 */ - if (solicited) - regex = g_regex_new (CREG2 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - else - regex = g_regex_new ("\\r\\n" CREG2 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - g_assert (regex); - g_ptr_array_add (array, regex); - - /* #3 */ - if (solicited) - regex = g_regex_new (CREG3 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - else - regex = g_regex_new ("\\r\\n" CREG3 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - g_assert (regex); - g_ptr_array_add (array, regex); - - /* #4 */ - if (solicited) - regex = g_regex_new (CREG4 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - else - regex = g_regex_new ("\\r\\n" CREG4 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - g_assert (regex); - g_ptr_array_add (array, regex); - - /* #5 */ - if (solicited) - regex = g_regex_new (CREG5 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - else - regex = g_regex_new ("\\r\\n" CREG5 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - g_assert (regex); - g_ptr_array_add (array, regex); - - /* #6 */ - if (solicited) - regex = g_regex_new (CREG6 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - else - regex = g_regex_new ("\\r\\n" CREG6 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - g_assert (regex); - g_ptr_array_add (array, regex); - - /* #7 */ - if (solicited) - regex = g_regex_new (CREG7 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - else - regex = g_regex_new ("\\r\\n" CREG7 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - g_assert (regex); - g_ptr_array_add (array, regex); - - /* #8 */ - if (solicited) - regex = g_regex_new (CREG8 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - else - regex = g_regex_new ("\\r\\n" CREG8 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - g_assert (regex); - g_ptr_array_add (array, regex); - - return array; -} - -void -mm_3gpp_creg_regex_destroy (GPtrArray *array) -{ - g_ptr_array_foreach (array, (GFunc) g_regex_unref, NULL); - g_ptr_array_free (array, TRUE); -} - -/*************************************************************************/ - -GRegex * -mm_3gpp_ciev_regex_get (void) -{ - return g_regex_new ("\\r\\n\\+CIEV: (.*),(\\d)\\r\\n", - G_REGEX_RAW | G_REGEX_OPTIMIZE, - 0, - NULL); -} - -/*************************************************************************/ - -GRegex * -mm_3gpp_cusd_regex_get (void) -{ - return g_regex_new ("\\r\\n\\+CUSD:\\s*(.*)\\r\\n", - G_REGEX_RAW | G_REGEX_OPTIMIZE, - 0, - NULL); -} - -/*************************************************************************/ - -GRegex * -mm_3gpp_cmti_regex_get (void) -{ - return g_regex_new ("\\r\\n\\+CMTI: \"(\\S+)\",(\\d+)\\r\\n", - G_REGEX_RAW | G_REGEX_OPTIMIZE, - 0, - NULL); -} - -/*************************************************************************/ - static gulong parse_uint (char *str, int base, glong nmin, glong nmax, gboolean *valid) { gulong ret = 0; - char *endquote; + gchar *endquote; *valid = FALSE; if (!str) @@ -687,7 +629,7 @@ parse_uint (char *str, int base, glong nmin, glong nmax, gboolean *valid) static gboolean item_is_lac_not_stat (GMatchInfo *info, guint32 item) { - char *str; + gchar *str; gboolean is_lac = FALSE; /* A <stat> will always be a single digit, without quotes */ @@ -711,7 +653,7 @@ mm_3gpp_parse_creg_response (GMatchInfo *info, gint n_matches, act = -1; gulong stat = 0, lac = 0, ci = 0; guint istat = 0, ilac = 0, ici = 0, iact = 0; - char *str; + gchar *str; g_return_val_if_fail (info != NULL, FALSE); g_return_val_if_fail (out_reg_state != NULL, FALSE); @@ -831,285 +773,163 @@ mm_3gpp_parse_creg_response (GMatchInfo *info, /*************************************************************************/ +#define CMGF_TAG "+CMGF:" + gboolean -mm_cdma_parse_spservice_response (const char *reply, - MMModemCdmaRegistrationState *out_cdma_1x_state, - MMModemCdmaRegistrationState *out_evdo_state) +mm_3gpp_parse_cmgf_test_response (const gchar *reply, + gboolean *sms_pdu_supported, + gboolean *sms_text_supported, + GError **error) { - const char *p; + GRegex *r; + GMatchInfo *match_info; + gchar *s; + guint32 min = -1, max = -1; - g_return_val_if_fail (reply != NULL, FALSE); - g_return_val_if_fail (out_cdma_1x_state != NULL, FALSE); - g_return_val_if_fail (out_evdo_state != NULL, FALSE); + /* Strip whitespace and response tag */ + if (g_str_has_prefix (reply, CMGF_TAG)) + reply += strlen (CMGF_TAG); + while (isspace (*reply)) + reply++; - p = mm_strip_tag (reply, "+SPSERVICE:"); - if (!isdigit (*p)) + r = g_regex_new ("\\(?\\s*(\\d+)\\s*[-,]?\\s*(\\d+)?\\s*\\)?", 0, 0, error); + if (!r) return FALSE; - switch (atoi (p)) { - case 0: /* no service */ - *out_cdma_1x_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN; - *out_evdo_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN; - break; - case 1: /* 1xRTT */ - *out_cdma_1x_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED; - *out_evdo_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN; - break; - case 2: /* EVDO rev 0 */ - case 3: /* EVDO rev A */ - *out_cdma_1x_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN; - *out_evdo_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED; - break; - default: + if (!g_regex_match_full (r, reply, strlen (reply), 0, 0, &match_info, NULL)) { + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Failed to parse CMGF query result '%s'", + reply); + g_match_info_free (match_info); + g_regex_unref (r); return FALSE; } + + s = g_match_info_fetch (match_info, 1); + if (s) + min = atoi (s); + g_free (s); + + s = g_match_info_fetch (match_info, 2); + if (s) + max = atoi (s); + g_free (s); + + /* CMGF=0 for PDU mode */ + *sms_pdu_supported = (min == 0); + + /* CMGF=1 for Text mode */ + *sms_text_supported = (max >= 1); + + g_match_info_free (match_info); + g_regex_unref (r); return TRUE; } /*************************************************************************/ -typedef struct { - int num; - gboolean roam_ind; - const char *banner; -} EriItem; - -/* NOTE: these may be Sprint-specific for now... */ -static const EriItem eris[] = { - { 0, TRUE, "Digital or Analog Roaming" }, - { 1, FALSE, "Home" }, - { 2, TRUE, "Digital or Analog Roaming" }, - { 3, TRUE, "Out of neighborhood" }, - { 4, TRUE, "Out of building" }, - { 5, TRUE, "Preferred system" }, - { 6, TRUE, "Available System" }, - { 7, TRUE, "Alliance Partner" }, - { 8, TRUE, "Premium Partner" }, - { 9, TRUE, "Full Service Functionality" }, - { 10, TRUE, "Partial Service Functionality" }, - { 64, TRUE, "Preferred system" }, - { 65, TRUE, "Available System" }, - { 66, TRUE, "Alliance Partner" }, - { 67, TRUE, "Premium Partner" }, - { 68, TRUE, "Full Service Functionality" }, - { 69, TRUE, "Partial Service Functionality" }, - { 70, TRUE, "Analog A" }, - { 71, TRUE, "Analog B" }, - { 72, TRUE, "CDMA 800 A" }, - { 73, TRUE, "CDMA 800 B" }, - { 74, TRUE, "International Roaming" }, - { 75, TRUE, "Extended Network" }, - { 76, FALSE, "Campus" }, - { 77, FALSE, "In Building" }, - { 78, TRUE, "Regional" }, - { 79, TRUE, "Community" }, - { 80, TRUE, "Business" }, - { 81, TRUE, "Zone 1" }, - { 82, TRUE, "Zone 2" }, - { 83, TRUE, "National" }, - { 84, TRUE, "Local" }, - { 85, TRUE, "City" }, - { 86, TRUE, "Government" }, - { 87, TRUE, "USA" }, - { 88, TRUE, "State" }, - { 89, TRUE, "Resort" }, - { 90, TRUE, "Headquarters" }, - { 91, TRUE, "Personal" }, - { 92, FALSE, "Home" }, - { 93, TRUE, "Residential" }, - { 94, TRUE, "University" }, - { 95, TRUE, "College" }, - { 96, TRUE, "Hotel Guest" }, - { 97, TRUE, "Rental" }, - { 98, FALSE, "Corporate" }, - { 99, FALSE, "Home Provider" }, - { 100, FALSE, "Campus" }, - { 101, FALSE, "In Building" }, - { 102, TRUE, "Regional" }, - { 103, TRUE, "Community" }, - { 104, TRUE, "Business" }, - { 105, TRUE, "Zone 1" }, - { 106, TRUE, "Zone 2" }, - { 107, TRUE, "National" }, - { 108, TRUE, "Local" }, - { 109, TRUE, "City" }, - { 110, TRUE, "Government" }, - { 111, TRUE, "USA" }, - { 112, TRUE, "State" }, - { 113, TRUE, "Resort" }, - { 114, TRUE, "Headquarters" }, - { 115, TRUE, "Personal" }, - { 116, FALSE, "Home" }, - { 117, TRUE, "Residential" }, - { 118, TRUE, "University" }, - { 119, TRUE, "College" }, - { 120, TRUE, "Hotel Guest" }, - { 121, TRUE, "Rental" }, - { 122, FALSE, "Corporate" }, - { 123, FALSE, "Home Provider" }, - { 124, TRUE, "International" }, - { 125, TRUE, "International" }, - { 126, TRUE, "International" }, - { 127, FALSE, "Premium Service" }, - { 128, FALSE, "Enhanced Service" }, - { 129, FALSE, "Enhanced Digital" }, - { 130, FALSE, "Enhanced Roaming" }, - { 131, FALSE, "Alliance Service" }, - { 132, FALSE, "Alliance Network" }, - { 133, FALSE, "Data Roaming" }, /* Sprint: Vision Roaming */ - { 134, FALSE, "Extended Service" }, - { 135, FALSE, "Expanded Services" }, - { 136, FALSE, "Expanded Network" }, - { 137, TRUE, "Premium Service" }, - { 138, TRUE, "Enhanced Service" }, - { 139, TRUE, "Enhanced Digital" }, - { 140, TRUE, "Enhanced Roaming" }, - { 141, TRUE, "Alliance Service" }, - { 142, TRUE, "Alliance Network" }, - { 143, TRUE, "Data Roaming" }, /* Sprint: Vision Roaming */ - { 144, TRUE, "Extended Service" }, - { 145, TRUE, "Expanded Services" }, - { 146, TRUE, "Expanded Network" }, - { 147, TRUE, "Premium Service" }, - { 148, TRUE, "Enhanced Service" }, - { 149, TRUE, "Enhanced Digital" }, - { 150, TRUE, "Enhanced Roaming" }, - { 151, TRUE, "Alliance Service" }, - { 152, TRUE, "Alliance Network" }, - { 153, TRUE, "Data Roaming" }, /* Sprint: Vision Roaming */ - { 154, TRUE, "Extended Service" }, - { 155, TRUE, "Expanded Services" }, - { 156, TRUE, "Expanded Network" }, - { 157, TRUE, "Premium International" }, - { 158, TRUE, "Premium International" }, - { 159, TRUE, "Premium International" }, - { 160, TRUE, NULL }, - { 161, TRUE, NULL }, - { 162, FALSE, NULL }, - { 163, FALSE, NULL }, - { 164, FALSE, "Extended Voice/Data Network" }, - { 165, FALSE, "Extended Voice/Data Network" }, - { 166, TRUE, "Extended Voice/Data Network" }, - { 167, FALSE, "Extended Broadband" }, - { 168, FALSE, "Extended Broadband" }, - { 169, TRUE, "Extended Broadband" }, - { 170, FALSE, "Extended Data" }, - { 171, FALSE, "Extended Data" }, - { 172, TRUE, "Extended Data" }, - { 173, FALSE, "Extended Data Network" }, - { 174, FALSE, "Extended Data Network" }, - { 175, TRUE, "Extended Data Network" }, - { 176, FALSE, "Extended Network" }, - { 177, FALSE, "Extended Network" }, - { 178, TRUE, "Extended Network" }, - { 179, FALSE, "Extended Service" }, - { 180, TRUE, "Extended Service" }, - { 181, FALSE, "Extended Voice" }, - { 182, FALSE, "Extended Voice" }, - { 183, TRUE, "Extended Voice" }, - { 184, FALSE, "Extended Voice/Data" }, - { 185, FALSE, "Extended Voice/Data" }, - { 186, TRUE, "Extended Voice/Data" }, - { 187, FALSE, "Extended Voice Network" }, - { 188, FALSE, "Extended Voice Network" }, - { 189, TRUE, "Extended Voice Network" }, - { 190, FALSE, "Extended Voice/Data" }, - { 191, FALSE, "Extended Voice/Data" }, - { 192, TRUE, "Extended Voice/Data" }, - { 193, TRUE, "International" }, - { 194, FALSE, "International Services" }, - { 195, FALSE, "International Voice" }, - { 196, FALSE, "International Voice/Data" }, - { 197, FALSE, "International Voice/Data" }, - { 198, TRUE, "International Voice/Data" }, - { 199, FALSE, "Extended Voice/Data Network" }, - { 200, TRUE, "Extended Voice/Data Network" }, - { 201, TRUE, "Extended Voice/Data Network" }, - { 202, FALSE, "Extended Broadband" }, - { 203, TRUE, "Extended Broadband" }, - { 204, TRUE, "Extended Broadband" }, - { 205, FALSE, "Extended Data" }, - { 206, TRUE, "Extended Data" }, - { 207, TRUE, "Extended Data" }, - { 208, FALSE, "Extended Data Network" }, - { 209, TRUE, "Extended Data Network" }, - { 210, TRUE, "Extended Data Network" }, - { 211, FALSE, "Extended Network" }, - { 212, TRUE, "Extended Network" }, - { 213, FALSE, "Extended Service" }, - { 214, TRUE, "Extended Service" }, - { 215, TRUE, "Extended Service" }, - { 216, FALSE, "Extended Voice" }, - { 217, TRUE, "Extended Voice" }, - { 218, TRUE, "Extended Voice" }, - { 219, FALSE, "Extended Voice/Data" }, - { 220, TRUE, "Extended Voice/Data" }, - { 221, TRUE, "Extended Voice/Data" }, - { 222, FALSE, "Extended Voice Network" }, - { 223, FALSE, "Extended Voice Network" }, - { 224, TRUE, "Extended Voice Network" }, - { 225, FALSE, "Extended Voice/Data" }, - { 226, TRUE, "Extended Voice/Data" }, - { 227, TRUE, "Extended Voice/Data" }, - { 228, TRUE, "International" }, - { 229, TRUE, "International" }, - { 230, TRUE, "International Services" }, - { 231, TRUE, "International Voice" }, - { 232, FALSE, "International Voice/Data" }, - { 233, TRUE, "International Voice/Data" }, - { 234, TRUE, "International Voice/Data" }, - { 235, TRUE, "Premium International" }, - { 236, TRUE, NULL }, - { 237, TRUE, NULL }, - { 238, FALSE, NULL }, - { 239, FALSE, NULL }, - { -1, FALSE, NULL }, -}; +static MMSmsStorage +storage_from_str (const gchar *str) +{ + if (g_str_equal (str, "SM")) + return MM_SMS_STORAGE_SM; + if (g_str_equal (str, "ME")) + return MM_SMS_STORAGE_ME; + if (g_str_equal (str, "MT")) + return MM_SMS_STORAGE_MT; + if (g_str_equal (str, "SR")) + return MM_SMS_STORAGE_SR; + if (g_str_equal (str, "BM")) + return MM_SMS_STORAGE_BM; + if (g_str_equal (str, "TA")) + return MM_SMS_STORAGE_TA; + return MM_SMS_STORAGE_UNKNOWN; +} gboolean -mm_cdma_parse_eri (const char *reply, - gboolean *out_roaming, - guint32 *out_ind, - const char **out_desc) +mm_3gpp_parse_cpms_test_response (const gchar *reply, + GArray **mem1, + GArray **mem2, + GArray **mem3) { - long int ind; - const EriItem *iter = &eris[0]; - gboolean found = FALSE; + GRegex *r; + gchar **split; + guint i; - g_return_val_if_fail (reply != NULL, FALSE); - g_return_val_if_fail (out_roaming != NULL, FALSE); + g_assert (mem1 != NULL); + g_assert (mem2 != NULL); + g_assert (mem3 != NULL); - errno = 0; - ind = strtol (reply, NULL, 10); - if (errno == 0) { - if (out_ind) - *out_ind = ind; + /* + * +CPMS: ("SM","ME"),("SM","ME"),("SM","ME") + */ + split = g_strsplit_set (mm_strip_tag (reply, "+CPMS:"), "()", -1); + if (!split) + return FALSE; - while (iter->num != -1) { - if (iter->num == ind) { - *out_roaming = iter->roam_ind; - if (out_desc) - *out_desc = iter->banner; - found = TRUE; - break; + r = g_regex_new ("\\s*\"([^,\\)]+)\"\\s*", 0, 0, NULL); + g_assert (r); + + for (i = 0; split[i]; i++) { + GMatchInfo *match_info; + + /* Got a range group to match */ + if (g_regex_match_full (r, split[i], strlen (split[i]), 0, 0, &match_info, NULL)) { + GArray *array = NULL; + + while (g_match_info_matches (match_info)) { + gchar *str; + + str = g_match_info_fetch (match_info, 1); + if (str) { + MMSmsStorage storage; + + if (!array) + array = g_array_new (FALSE, FALSE, sizeof (MMSmsStorage)); + + storage = storage_from_str (str); + g_array_append_val (array, storage); + g_free (str); + } + + g_match_info_next (match_info, NULL); } - iter++; + + if (!*mem1) + *mem1 = array; + else if (!*mem2) + *mem2 = array; + else if (!*mem3) + *mem3 = array; } + g_match_info_free (match_info); + + if (*mem3 != NULL) + break; /* once we got the last group, exit... */ } - return found; + g_strfreev (split); + g_regex_unref (r); + + g_warn_if_fail (*mem1 != NULL); + g_warn_if_fail (*mem2 != NULL); + g_warn_if_fail (*mem3 != NULL); + + return (*mem1 && *mem2 && *mem3); } /*************************************************************************/ gboolean -mm_gsm_parse_cscs_support_response (const char *reply, - MMModemCharset *out_charsets) +mm_3gpp_parse_cscs_test_response (const gchar *reply, + MMModemCharset *out_charsets) { MMModemCharset charsets = MM_MODEM_CHARSET_UNKNOWN; GRegex *r; GMatchInfo *match_info; - char *p, *str; + gchar *p, *str; gboolean success = FALSE; g_return_val_if_fail (reply != NULL, FALSE); @@ -1156,97 +976,6 @@ mm_gsm_parse_cscs_support_response (const char *reply, /*************************************************************************/ -gchar * -mm_3gpp_parse_operator (const gchar *reply, - MMModemCharset cur_charset) -{ - gchar *operator = NULL; - - if (reply && !strncmp (reply, "+COPS: ", 7)) { - /* Got valid reply */ - GRegex *r; - GMatchInfo *match_info; - - reply += 7; - r = g_regex_new ("(\\d),(\\d),\"(.+)\"", G_REGEX_UNGREEDY, 0, NULL); - if (!r) - return NULL; - - g_regex_match (r, reply, 0, &match_info); - if (g_match_info_matches (match_info)) - operator = g_match_info_fetch (match_info, 3); - - g_match_info_free (match_info); - g_regex_unref (r); - } - - if (operator) { - /* Some modems (Option & HSO) return the operator name as a hexadecimal - * string of the bytes of the operator name as encoded by the current - * character set. - */ - if (cur_charset == MM_MODEM_CHARSET_UCS2) - operator = mm_charset_take_and_convert_to_utf8 (operator, MM_MODEM_CHARSET_UCS2); - - /* Ensure the operator name is valid UTF-8 so that we can send it - * through D-Bus and such. - */ - if (!g_utf8_validate (operator, -1, NULL)) { - g_free (operator); - operator = NULL; - } - } - - return operator; -} - -/*************************************************************************/ - -/* Map two letter facility codes into flag values. There are - * many more facilities defined (for various flavors of call - * barring); we only map the ones we care about. */ -typedef struct { - MMModem3gppFacility facility; - gchar *acronym; -} FacilityAcronym; - -static const FacilityAcronym facility_acronyms[] = { - { MM_MODEM_3GPP_FACILITY_SIM, "SC" }, - { MM_MODEM_3GPP_FACILITY_PH_SIM, "PS" }, - { MM_MODEM_3GPP_FACILITY_PH_FSIM, "PF" }, - { MM_MODEM_3GPP_FACILITY_FIXED_DIALING, "FD" }, - { MM_MODEM_3GPP_FACILITY_NET_PERS, "PN" }, - { MM_MODEM_3GPP_FACILITY_NET_SUB_PERS, "PU" }, - { MM_MODEM_3GPP_FACILITY_PROVIDER_PERS, "PP" }, - { MM_MODEM_3GPP_FACILITY_CORP_PERS, "PC" } -}; - -static MMModem3gppFacility -string_to_facility (const gchar *str) -{ - guint i; - - for (i = 0; i < G_N_ELEMENTS (facility_acronyms); i++) { - if (g_str_equal (facility_acronyms[i].acronym, str)) - return facility_acronyms[i].facility; - } - - return MM_MODEM_3GPP_FACILITY_NONE; -} - -gchar * -mm_3gpp_get_facility_acronym (MMModem3gppFacility facility) -{ - guint i; - - for (i = 0; i < G_N_ELEMENTS (facility_acronyms); i++) { - if (facility_acronyms[i].facility == facility) - return facility_acronyms[i].acronym; - } - - return NULL; -} - gboolean mm_3gpp_parse_clck_test_response (const gchar *reply, MMModem3gppFacility *out_facilities) @@ -1274,7 +1003,7 @@ mm_3gpp_parse_clck_test_response (const gchar *reply, str = g_match_info_fetch (match_info, 1); if (str) { - *out_facilities |= string_to_facility (str); + *out_facilities |= mm_3gpp_acronym_to_facility (str); g_free (str); } @@ -1287,9 +1016,11 @@ mm_3gpp_parse_clck_test_response (const gchar *reply, return (*out_facilities != MM_MODEM_3GPP_FACILITY_NONE); } +/*************************************************************************/ + gboolean -mm_3gpp_parse_clck_response (const gchar *reply, - gboolean *enabled) +mm_3gpp_parse_clck_write_response (const gchar *reply, + gboolean *enabled) { GRegex *r; GMatchInfo *match_info; @@ -1329,139 +1060,62 @@ mm_3gpp_parse_clck_response (const gchar *reply, /*************************************************************************/ -MMModemAccessTechnology -mm_3gpp_string_to_access_tech (const gchar *string) -{ - MMModemAccessTechnology act = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; - - g_return_val_if_fail (string != NULL, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN); - - /* We're returning a MASK of technologies found; so we can include more - * than one technology in the result */ - if (strcasestr (string, "LTE")) - act |= MM_MODEM_ACCESS_TECHNOLOGY_LTE; - - if (strcasestr (string, "HSPA+")) - act |= MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS; - else if (strcasestr (string, "HSPA")) - act |= MM_MODEM_ACCESS_TECHNOLOGY_HSPA; - - - if (strcasestr (string, "HSUPA")) - act |= MM_MODEM_ACCESS_TECHNOLOGY_HSUPA; - - if (strcasestr (string, "HSDPA")) - act |= MM_MODEM_ACCESS_TECHNOLOGY_HSDPA; - - if (strcasestr (string, "UMTS")) - act |= MM_MODEM_ACCESS_TECHNOLOGY_UMTS; - - if (strcasestr (string, "EDGE")) - act |= MM_MODEM_ACCESS_TECHNOLOGY_EDGE; - - if (strcasestr (string, "GPRS")) - act |= MM_MODEM_ACCESS_TECHNOLOGY_GPRS; - - if (strcasestr (string, "GSM")) - act |= MM_MODEM_ACCESS_TECHNOLOGY_GSM; - - return act; -} - -/*************************************************************************/ - -char * -mm_create_device_identifier (guint vid, - guint pid, - const char *ati, - const char *ati1, - const char *gsn, - const char *revision, - const char *model, - const char *manf) +GStrv +mm_3gpp_parse_cnum_exec_response (const gchar *reply, + GError **error) { - GString *devid, *msg = NULL; - GChecksum *sum; - char *p, *ret = NULL; - char str_vid[10], str_pid[10]; - - /* Build up the device identifier */ - devid = g_string_sized_new (50); - if (ati) - g_string_append (devid, ati); - if (ati1) { - /* Only append "ATI1" if it's differnet than "ATI" */ - if (!ati || (strcmp (ati, ati1) != 0)) - g_string_append (devid, ati1); - } - if (gsn) - g_string_append (devid, gsn); - if (revision) - g_string_append (devid, revision); - if (model) - g_string_append (devid, model); - if (manf) - g_string_append (devid, manf); + GArray *array = NULL; + GRegex *r; + GMatchInfo *match_info; - if (!strlen (devid->str)) { - g_string_free (devid, TRUE); + /* Empty strings also return NULL list */ + if (!reply || !reply[0]) return NULL; - } - p = devid->str; - msg = g_string_sized_new (strlen (devid->str) + 17); + r = g_regex_new ("\\+CNUM:\\s*\"?\\S*\"?,\"(\\S+)\",\\d", G_REGEX_UNGREEDY, 0, NULL); + g_assert (r != NULL); - sum = g_checksum_new (G_CHECKSUM_SHA1); + g_regex_match (r, reply, 0, &match_info); + while (g_match_info_matches (match_info)) { + gchar *number; - if (vid) { - snprintf (str_vid, sizeof (str_vid) - 1, "%08x", vid); - g_checksum_update (sum, (const guchar *) &str_vid[0], strlen (str_vid)); - g_string_append_printf (msg, "%08x", vid); - } - if (vid) { - snprintf (str_pid, sizeof (str_pid) - 1, "%08x", pid); - g_checksum_update (sum, (const guchar *) &str_pid[0], strlen (str_pid)); - g_string_append_printf (msg, "%08x", pid); - } + number = g_match_info_fetch (match_info, 1); - while (*p) { - /* Strip spaces and linebreaks */ - if (!isblank (*p) && !isspace (*p) && isascii (*p)) { - g_checksum_update (sum, (const guchar *) p, 1); - g_string_append_c (msg, *p); - } - p++; + if (number && number[0]) { + if (!array) + array = g_array_new (TRUE, TRUE, sizeof (gchar *)); + g_array_append_val (array, number); + } else + g_free (number); + + g_match_info_next (match_info, NULL); } - ret = g_strdup (g_checksum_get_string (sum)); - g_checksum_free (sum); - mm_dbg ("Device ID source '%s'", msg->str); - mm_dbg ("Device ID '%s'", ret); - g_string_free (msg, TRUE); - g_string_free (devid, TRUE); + g_match_info_free (match_info); + g_regex_unref (r); - return ret; + return (array ? (GStrv) g_array_free (array, FALSE) : NULL); } /*************************************************************************/ -struct CindResponse { - char *desc; +struct MM3gppCindResponse { + gchar *desc; guint idx; gint min; gint max; }; -static CindResponse * -cind_response_new (const char *desc, guint idx, gint min, gint max) +static MM3gppCindResponse * +cind_response_new (const gchar *desc, guint idx, gint min, gint max) { - CindResponse *r; - char *p; + MM3gppCindResponse *r; + gchar *p; g_return_val_if_fail (desc != NULL, NULL); g_return_val_if_fail (idx >= 0, NULL); - r = g_malloc0 (sizeof (CindResponse)); + r = g_malloc0 (sizeof (MM3gppCindResponse)); /* Strip quotes */ r->desc = p = g_malloc0 (strlen (desc) + 1); @@ -1478,17 +1132,17 @@ cind_response_new (const char *desc, guint idx, gint min, gint max) } static void -cind_response_free (CindResponse *r) +cind_response_free (MM3gppCindResponse *r) { g_return_if_fail (r != NULL); g_free (r->desc); - memset (r, 0, sizeof (CindResponse)); + memset (r, 0, sizeof (MM3gppCindResponse)); g_free (r); } -const char * -cind_response_get_desc (CindResponse *r) +const gchar * +mm_3gpp_cind_response_get_desc (MM3gppCindResponse *r) { g_return_val_if_fail (r != NULL, NULL); @@ -1496,7 +1150,7 @@ cind_response_get_desc (CindResponse *r) } guint -cind_response_get_index (CindResponse *r) +mm_3gpp_cind_response_get_index (MM3gppCindResponse *r) { g_return_val_if_fail (r != NULL, 0); @@ -1504,7 +1158,7 @@ cind_response_get_index (CindResponse *r) } gint -cind_response_get_min (CindResponse *r) +mm_3gpp_cind_response_get_min (MM3gppCindResponse *r) { g_return_val_if_fail (r != NULL, -1); @@ -1512,7 +1166,7 @@ cind_response_get_min (CindResponse *r) } gint -cind_response_get_max (CindResponse *r) +mm_3gpp_cind_response_get_max (MM3gppCindResponse *r) { g_return_val_if_fail (r != NULL, -1); @@ -1522,7 +1176,8 @@ cind_response_get_max (CindResponse *r) #define CIND_TAG "+CIND:" GHashTable * -mm_parse_cind_test_response (const char *reply, GError **error) +mm_3gpp_parse_cind_test_response (const gchar *reply, + GError **error) { GHashTable *hash; GRegex *r; @@ -1549,8 +1204,8 @@ mm_parse_cind_test_response (const char *reply, GError **error) if (g_regex_match_full (r, reply, strlen (reply), 0, 0, &match_info, NULL)) { while (g_match_info_matches (match_info)) { - CindResponse *resp; - char *desc, *tmp; + MM3gppCindResponse *resp; + gchar *desc, *tmp; gint min = 0, max = 0; desc = g_match_info_fetch (match_info, 1); @@ -1578,11 +1233,14 @@ mm_parse_cind_test_response (const char *reply, GError **error) return hash; } +/*************************************************************************/ + GByteArray * -mm_parse_cind_query_response(const char *reply, GError **error) +mm_3gpp_parse_cind_read_response (const gchar *reply, + GError **error) { GByteArray *array = NULL; - const char *p = reply; + const gchar *p = reply; GRegex *r = NULL; GMatchInfo *match_info; guint8 t = 0; @@ -1615,12 +1273,12 @@ mm_parse_cind_query_response(const char *reply, GError **error) array = g_byte_array_sized_new (g_match_info_get_match_count (match_info)); /* Add a zero element so callers can use 1-based indexes returned by - * cind_response_get_index(). + * mm_3gpp_cind_response_get_index(). */ g_byte_array_append (array, &t, 1); while (g_match_info_matches (match_info)) { - char *str; + gchar *str; gulong val; str = g_match_info_fetch (match_info, 1); @@ -1645,116 +1303,418 @@ done: return array; } -gint -mm_cdma_normalize_class (const gchar *orig_class) +/*************************************************************************/ + +/* Map two letter facility codes into flag values. There are + * many more facilities defined (for various flavors of call + * barring); we only map the ones we care about. */ +typedef struct { + MMModem3gppFacility facility; + gchar *acronym; +} FacilityAcronym; + +static const FacilityAcronym facility_acronyms[] = { + { MM_MODEM_3GPP_FACILITY_SIM, "SC" }, + { MM_MODEM_3GPP_FACILITY_PH_SIM, "PS" }, + { MM_MODEM_3GPP_FACILITY_PH_FSIM, "PF" }, + { MM_MODEM_3GPP_FACILITY_FIXED_DIALING, "FD" }, + { MM_MODEM_3GPP_FACILITY_NET_PERS, "PN" }, + { MM_MODEM_3GPP_FACILITY_NET_SUB_PERS, "PU" }, + { MM_MODEM_3GPP_FACILITY_PROVIDER_PERS, "PP" }, + { MM_MODEM_3GPP_FACILITY_CORP_PERS, "PC" } +}; + +MMModem3gppFacility +mm_3gpp_acronym_to_facility (const gchar *str) { - gchar class; + guint i; - g_return_val_if_fail (orig_class != NULL, '0'); + for (i = 0; i < G_N_ELEMENTS (facility_acronyms); i++) { + if (g_str_equal (facility_acronyms[i].acronym, str)) + return facility_acronyms[i].facility; + } - class = toupper (orig_class[0]); + return MM_MODEM_3GPP_FACILITY_NONE; +} - /* Cellular (850MHz) */ - if (class == '1' || class == 'C') - return 1; - /* PCS (1900MHz) */ - if (class == '2' || class == 'P') - return 2; +gchar * +mm_3gpp_facility_to_acronym (MMModem3gppFacility facility) +{ + guint i; - /* Unknown/not registered */ - return 0; + for (i = 0; i < G_N_ELEMENTS (facility_acronyms); i++) { + if (facility_acronyms[i].facility == facility) + return facility_acronyms[i].acronym; + } + + return NULL; } -gchar -mm_cdma_normalize_band (const gchar *long_band, - gint *out_class) +/*************************************************************************/ + +MMModemAccessTechnology +mm_3gpp_string_to_access_tech (const gchar *string) { - gchar band; + MMModemAccessTechnology act = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; - g_return_val_if_fail (long_band != NULL, 'Z'); + g_return_val_if_fail (string != NULL, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN); - /* There are two response formats for the band; one includes the band - * class and the other doesn't. For modems that include the band class - * (ex Novatel S720) you'll see "Px" or "Cx" depending on whether the modem - * is registered on a PCS/1900 (P) or Cellular/850 (C) system. - */ - band = toupper (long_band[0]); + /* We're returning a MASK of technologies found; so we can include more + * than one technology in the result */ + if (strcasestr (string, "LTE")) + act |= MM_MODEM_ACCESS_TECHNOLOGY_LTE; - /* Possible band class in first position; return it */ - if (band == 'C' || band == 'P') { - gchar tmp[2] = { band, '\0' }; + if (strcasestr (string, "HSPA+")) + act |= MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS; + else if (strcasestr (string, "HSPA")) + act |= MM_MODEM_ACCESS_TECHNOLOGY_HSPA; - *out_class = mm_cdma_normalize_class (tmp); - band = toupper (long_band[1]); - } - /* normalize to A - F, and Z */ - if (band >= 'A' && band <= 'F') - return band; + if (strcasestr (string, "HSUPA")) + act |= MM_MODEM_ACCESS_TECHNOLOGY_HSUPA; - /* Unknown/not registered */ - return 'Z'; + if (strcasestr (string, "HSDPA")) + act |= MM_MODEM_ACCESS_TECHNOLOGY_HSDPA; + + if (strcasestr (string, "UMTS")) + act |= MM_MODEM_ACCESS_TECHNOLOGY_UMTS; + + if (strcasestr (string, "EDGE")) + act |= MM_MODEM_ACCESS_TECHNOLOGY_EDGE; + + if (strcasestr (string, "GPRS")) + act |= MM_MODEM_ACCESS_TECHNOLOGY_GPRS; + + if (strcasestr (string, "GSM")) + act |= MM_MODEM_ACCESS_TECHNOLOGY_GSM; + + return act; } -gint -mm_cdma_convert_sid (const gchar *sid) +/*************************************************************************/ + +gchar * +mm_3gpp_parse_operator (const gchar *reply, + MMModemCharset cur_charset) { - glong tmp_sid; + gchar *operator = NULL; - g_return_val_if_fail (sid != NULL, MM_MODEM_CDMA_SID_UNKNOWN); + if (reply && !strncmp (reply, "+COPS: ", 7)) { + /* Got valid reply */ + GRegex *r; + GMatchInfo *match_info; - errno = 0; - tmp_sid = strtol (sid, NULL, 10); - if ((errno == EINVAL) || (errno == ERANGE)) - return MM_MODEM_CDMA_SID_UNKNOWN; - else if (tmp_sid < G_MININT || tmp_sid > G_MAXINT) - return MM_MODEM_CDMA_SID_UNKNOWN; + reply += 7; + r = g_regex_new ("(\\d),(\\d),\"(.+)\"", G_REGEX_UNGREEDY, 0, NULL); + if (!r) + return NULL; - return (gint) tmp_sid; + g_regex_match (r, reply, 0, &match_info); + if (g_match_info_matches (match_info)) + operator = g_match_info_fetch (match_info, 3); + + g_match_info_free (match_info); + g_regex_unref (r); + } + + if (operator) { + /* Some modems (Option & HSO) return the operator name as a hexadecimal + * string of the bytes of the operator name as encoded by the current + * character set. + */ + if (cur_charset == MM_MODEM_CHARSET_UCS2) + operator = mm_charset_take_and_convert_to_utf8 (operator, MM_MODEM_CHARSET_UCS2); + + /* Ensure the operator name is valid UTF-8 so that we can send it + * through D-Bus and such. + */ + if (!g_utf8_validate (operator, -1, NULL)) { + g_free (operator); + operator = NULL; + } + } + + return operator; } -guint -mm_cdma_get_index_from_rm_protocol (MMModemCdmaRmProtocol protocol, - GError **error) +/*************************************************************************/ + +gboolean +mm_cdma_parse_spservice_read_response (const gchar *reply, + MMModemCdmaRegistrationState *out_cdma_1x_state, + MMModemCdmaRegistrationState *out_evdo_state) { - if (protocol == MM_MODEM_CDMA_RM_PROTOCOL_UNKNOWN) { - g_set_error (error, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Unexpected RM protocol (%s)", - mm_modem_cdma_rm_protocol_get_string (protocol)); - return 0; - } + const gchar *p; - /* just substracting 1 from the enum value should give us the index */ - return (protocol - 1); + g_return_val_if_fail (reply != NULL, FALSE); + g_return_val_if_fail (out_cdma_1x_state != NULL, FALSE); + g_return_val_if_fail (out_evdo_state != NULL, FALSE); + + p = mm_strip_tag (reply, "+SPSERVICE:"); + if (!isdigit (*p)) + return FALSE; + + switch (atoi (p)) { + case 0: /* no service */ + *out_cdma_1x_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN; + *out_evdo_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN; + break; + case 1: /* 1xRTT */ + *out_cdma_1x_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED; + *out_evdo_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN; + break; + case 2: /* EVDO rev 0 */ + case 3: /* EVDO rev A */ + *out_cdma_1x_state = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN; + *out_evdo_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED; + break; + default: + return FALSE; + } + return TRUE; } -MMModemCdmaRmProtocol -mm_cdma_get_rm_protocol_from_index (guint index, - GError **error) +/*************************************************************************/ + +typedef struct { + gint num; + gboolean roam_ind; + const gchar *banner; +} EriItem; + +/* NOTE: these may be Sprint-specific for now... */ +static const EriItem eris[] = { + { 0, TRUE, "Digital or Analog Roaming" }, + { 1, FALSE, "Home" }, + { 2, TRUE, "Digital or Analog Roaming" }, + { 3, TRUE, "Out of neighborhood" }, + { 4, TRUE, "Out of building" }, + { 5, TRUE, "Preferred system" }, + { 6, TRUE, "Available System" }, + { 7, TRUE, "Alliance Partner" }, + { 8, TRUE, "Premium Partner" }, + { 9, TRUE, "Full Service Functionality" }, + { 10, TRUE, "Partial Service Functionality" }, + { 64, TRUE, "Preferred system" }, + { 65, TRUE, "Available System" }, + { 66, TRUE, "Alliance Partner" }, + { 67, TRUE, "Premium Partner" }, + { 68, TRUE, "Full Service Functionality" }, + { 69, TRUE, "Partial Service Functionality" }, + { 70, TRUE, "Analog A" }, + { 71, TRUE, "Analog B" }, + { 72, TRUE, "CDMA 800 A" }, + { 73, TRUE, "CDMA 800 B" }, + { 74, TRUE, "International Roaming" }, + { 75, TRUE, "Extended Network" }, + { 76, FALSE, "Campus" }, + { 77, FALSE, "In Building" }, + { 78, TRUE, "Regional" }, + { 79, TRUE, "Community" }, + { 80, TRUE, "Business" }, + { 81, TRUE, "Zone 1" }, + { 82, TRUE, "Zone 2" }, + { 83, TRUE, "National" }, + { 84, TRUE, "Local" }, + { 85, TRUE, "City" }, + { 86, TRUE, "Government" }, + { 87, TRUE, "USA" }, + { 88, TRUE, "State" }, + { 89, TRUE, "Resort" }, + { 90, TRUE, "Headquarters" }, + { 91, TRUE, "Personal" }, + { 92, FALSE, "Home" }, + { 93, TRUE, "Residential" }, + { 94, TRUE, "University" }, + { 95, TRUE, "College" }, + { 96, TRUE, "Hotel Guest" }, + { 97, TRUE, "Rental" }, + { 98, FALSE, "Corporate" }, + { 99, FALSE, "Home Provider" }, + { 100, FALSE, "Campus" }, + { 101, FALSE, "In Building" }, + { 102, TRUE, "Regional" }, + { 103, TRUE, "Community" }, + { 104, TRUE, "Business" }, + { 105, TRUE, "Zone 1" }, + { 106, TRUE, "Zone 2" }, + { 107, TRUE, "National" }, + { 108, TRUE, "Local" }, + { 109, TRUE, "City" }, + { 110, TRUE, "Government" }, + { 111, TRUE, "USA" }, + { 112, TRUE, "State" }, + { 113, TRUE, "Resort" }, + { 114, TRUE, "Headquarters" }, + { 115, TRUE, "Personal" }, + { 116, FALSE, "Home" }, + { 117, TRUE, "Residential" }, + { 118, TRUE, "University" }, + { 119, TRUE, "College" }, + { 120, TRUE, "Hotel Guest" }, + { 121, TRUE, "Rental" }, + { 122, FALSE, "Corporate" }, + { 123, FALSE, "Home Provider" }, + { 124, TRUE, "International" }, + { 125, TRUE, "International" }, + { 126, TRUE, "International" }, + { 127, FALSE, "Premium Service" }, + { 128, FALSE, "Enhanced Service" }, + { 129, FALSE, "Enhanced Digital" }, + { 130, FALSE, "Enhanced Roaming" }, + { 131, FALSE, "Alliance Service" }, + { 132, FALSE, "Alliance Network" }, + { 133, FALSE, "Data Roaming" }, /* Sprint: Vision Roaming */ + { 134, FALSE, "Extended Service" }, + { 135, FALSE, "Expanded Services" }, + { 136, FALSE, "Expanded Network" }, + { 137, TRUE, "Premium Service" }, + { 138, TRUE, "Enhanced Service" }, + { 139, TRUE, "Enhanced Digital" }, + { 140, TRUE, "Enhanced Roaming" }, + { 141, TRUE, "Alliance Service" }, + { 142, TRUE, "Alliance Network" }, + { 143, TRUE, "Data Roaming" }, /* Sprint: Vision Roaming */ + { 144, TRUE, "Extended Service" }, + { 145, TRUE, "Expanded Services" }, + { 146, TRUE, "Expanded Network" }, + { 147, TRUE, "Premium Service" }, + { 148, TRUE, "Enhanced Service" }, + { 149, TRUE, "Enhanced Digital" }, + { 150, TRUE, "Enhanced Roaming" }, + { 151, TRUE, "Alliance Service" }, + { 152, TRUE, "Alliance Network" }, + { 153, TRUE, "Data Roaming" }, /* Sprint: Vision Roaming */ + { 154, TRUE, "Extended Service" }, + { 155, TRUE, "Expanded Services" }, + { 156, TRUE, "Expanded Network" }, + { 157, TRUE, "Premium International" }, + { 158, TRUE, "Premium International" }, + { 159, TRUE, "Premium International" }, + { 160, TRUE, NULL }, + { 161, TRUE, NULL }, + { 162, FALSE, NULL }, + { 163, FALSE, NULL }, + { 164, FALSE, "Extended Voice/Data Network" }, + { 165, FALSE, "Extended Voice/Data Network" }, + { 166, TRUE, "Extended Voice/Data Network" }, + { 167, FALSE, "Extended Broadband" }, + { 168, FALSE, "Extended Broadband" }, + { 169, TRUE, "Extended Broadband" }, + { 170, FALSE, "Extended Data" }, + { 171, FALSE, "Extended Data" }, + { 172, TRUE, "Extended Data" }, + { 173, FALSE, "Extended Data Network" }, + { 174, FALSE, "Extended Data Network" }, + { 175, TRUE, "Extended Data Network" }, + { 176, FALSE, "Extended Network" }, + { 177, FALSE, "Extended Network" }, + { 178, TRUE, "Extended Network" }, + { 179, FALSE, "Extended Service" }, + { 180, TRUE, "Extended Service" }, + { 181, FALSE, "Extended Voice" }, + { 182, FALSE, "Extended Voice" }, + { 183, TRUE, "Extended Voice" }, + { 184, FALSE, "Extended Voice/Data" }, + { 185, FALSE, "Extended Voice/Data" }, + { 186, TRUE, "Extended Voice/Data" }, + { 187, FALSE, "Extended Voice Network" }, + { 188, FALSE, "Extended Voice Network" }, + { 189, TRUE, "Extended Voice Network" }, + { 190, FALSE, "Extended Voice/Data" }, + { 191, FALSE, "Extended Voice/Data" }, + { 192, TRUE, "Extended Voice/Data" }, + { 193, TRUE, "International" }, + { 194, FALSE, "International Services" }, + { 195, FALSE, "International Voice" }, + { 196, FALSE, "International Voice/Data" }, + { 197, FALSE, "International Voice/Data" }, + { 198, TRUE, "International Voice/Data" }, + { 199, FALSE, "Extended Voice/Data Network" }, + { 200, TRUE, "Extended Voice/Data Network" }, + { 201, TRUE, "Extended Voice/Data Network" }, + { 202, FALSE, "Extended Broadband" }, + { 203, TRUE, "Extended Broadband" }, + { 204, TRUE, "Extended Broadband" }, + { 205, FALSE, "Extended Data" }, + { 206, TRUE, "Extended Data" }, + { 207, TRUE, "Extended Data" }, + { 208, FALSE, "Extended Data Network" }, + { 209, TRUE, "Extended Data Network" }, + { 210, TRUE, "Extended Data Network" }, + { 211, FALSE, "Extended Network" }, + { 212, TRUE, "Extended Network" }, + { 213, FALSE, "Extended Service" }, + { 214, TRUE, "Extended Service" }, + { 215, TRUE, "Extended Service" }, + { 216, FALSE, "Extended Voice" }, + { 217, TRUE, "Extended Voice" }, + { 218, TRUE, "Extended Voice" }, + { 219, FALSE, "Extended Voice/Data" }, + { 220, TRUE, "Extended Voice/Data" }, + { 221, TRUE, "Extended Voice/Data" }, + { 222, FALSE, "Extended Voice Network" }, + { 223, FALSE, "Extended Voice Network" }, + { 224, TRUE, "Extended Voice Network" }, + { 225, FALSE, "Extended Voice/Data" }, + { 226, TRUE, "Extended Voice/Data" }, + { 227, TRUE, "Extended Voice/Data" }, + { 228, TRUE, "International" }, + { 229, TRUE, "International" }, + { 230, TRUE, "International Services" }, + { 231, TRUE, "International Voice" }, + { 232, FALSE, "International Voice/Data" }, + { 233, TRUE, "International Voice/Data" }, + { 234, TRUE, "International Voice/Data" }, + { 235, TRUE, "Premium International" }, + { 236, TRUE, NULL }, + { 237, TRUE, NULL }, + { 238, FALSE, NULL }, + { 239, FALSE, NULL }, + { -1, FALSE, NULL }, +}; + +gboolean +mm_cdma_parse_speri_read_response (const gchar *reply, + gboolean *out_roaming, + guint32 *out_ind, + const gchar **out_desc) { - guint protocol; + glong ind; + const EriItem *iter = &eris[0]; + gboolean found = FALSE; - /* just adding 1 from the index value should give us the enum */ - protocol = index + 1 ; - if (protocol > MM_MODEM_CDMA_RM_PROTOCOL_STU_III) { - g_set_error (error, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Unexpected RM protocol index (%u)", - index); - protocol = MM_MODEM_CDMA_RM_PROTOCOL_UNKNOWN; + g_return_val_if_fail (reply != NULL, FALSE); + g_return_val_if_fail (out_roaming != NULL, FALSE); + + errno = 0; + ind = strtol (reply, NULL, 10); + if (errno == 0) { + if (out_ind) + *out_ind = ind; + + while (iter->num != -1) { + if (iter->num == ind) { + *out_roaming = iter->roam_ind; + if (out_desc) + *out_desc = iter->banner; + found = TRUE; + break; + } + iter++; + } } - return (MMModemCdmaRmProtocol)protocol; + return found; } +/*************************************************************************/ + gboolean -mm_cdma_parse_crm_range_response (const gchar *reply, - MMModemCdmaRmProtocol *min, - MMModemCdmaRmProtocol *max, - GError **error) +mm_cdma_parse_crm_test_response (const gchar *reply, + MMModemCdmaRmProtocol *min, + MMModemCdmaRmProtocol *max, + GError **error) { gboolean result = FALSE; GRegex *r; @@ -1811,49 +1771,115 @@ mm_cdma_parse_crm_range_response (const gchar *reply, return result; } +/*************************************************************************/ + +MMModemCdmaRmProtocol +mm_cdma_get_rm_protocol_from_index (guint index, + GError **error) +{ + guint protocol; + + /* just adding 1 from the index value should give us the enum */ + protocol = index + 1 ; + if (protocol > MM_MODEM_CDMA_RM_PROTOCOL_STU_III) { + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Unexpected RM protocol index (%u)", + index); + protocol = MM_MODEM_CDMA_RM_PROTOCOL_UNKNOWN; + } + + return (MMModemCdmaRmProtocol)protocol; +} + guint -mm_count_bits_set (gulong number) +mm_cdma_get_index_from_rm_protocol (MMModemCdmaRmProtocol protocol, + GError **error) { - guint c; + if (protocol == MM_MODEM_CDMA_RM_PROTOCOL_UNKNOWN) { + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Unexpected RM protocol (%s)", + mm_modem_cdma_rm_protocol_get_string (protocol)); + return 0; + } - for (c = 0; number; c++) - number &= number - 1; - return c; + /* just substracting 1 from the enum value should give us the index */ + return (protocol - 1); } -GStrv -mm_3gpp_parse_cnum_response (const gchar *reply, - GError **error) +/*************************************************************************/ + +gint +mm_cdma_normalize_class (const gchar *orig_class) { - GArray *array = NULL; - GRegex *r; - GMatchInfo *match_info; + gchar class; - /* Empty strings also return NULL list */ - if (!reply || !reply[0]) - return NULL; + g_return_val_if_fail (orig_class != NULL, '0'); - r = g_regex_new ("\\+CNUM:\\s*\"?\\S*\"?,\"(\\S+)\",\\d", G_REGEX_UNGREEDY, 0, NULL); - g_assert (r != NULL); + class = toupper (orig_class[0]); - g_regex_match (r, reply, 0, &match_info); - while (g_match_info_matches (match_info)) { - gchar *number; + /* Cellular (850MHz) */ + if (class == '1' || class == 'C') + return 1; + /* PCS (1900MHz) */ + if (class == '2' || class == 'P') + return 2; - number = g_match_info_fetch (match_info, 1); + /* Unknown/not registered */ + return 0; +} - if (number && number[0]) { - if (!array) - array = g_array_new (TRUE, TRUE, sizeof (gchar *)); - g_array_append_val (array, number); - } else - g_free (number); +/*************************************************************************/ - g_match_info_next (match_info, NULL); +gchar +mm_cdma_normalize_band (const gchar *long_band, + gint *out_class) +{ + gchar band; + + g_return_val_if_fail (long_band != NULL, 'Z'); + + /* There are two response formats for the band; one includes the band + * class and the other doesn't. For modems that include the band class + * (ex Novatel S720) you'll see "Px" or "Cx" depending on whether the modem + * is registered on a PCS/1900 (P) or Cellular/850 (C) system. + */ + band = toupper (long_band[0]); + + /* Possible band class in first position; return it */ + if (band == 'C' || band == 'P') { + gchar tmp[2] = { band, '\0' }; + + *out_class = mm_cdma_normalize_class (tmp); + band = toupper (long_band[1]); } - g_match_info_free (match_info); - g_regex_unref (r); + /* normalize to A - F, and Z */ + if (band >= 'A' && band <= 'F') + return band; - return (array ? (GStrv) g_array_free (array, FALSE) : NULL); + /* Unknown/not registered */ + return 'Z'; +} + +/*************************************************************************/ + +gint +mm_cdma_convert_sid (const gchar *sid) +{ + glong tmp_sid; + + g_return_val_if_fail (sid != NULL, MM_MODEM_CDMA_SID_UNKNOWN); + + errno = 0; + tmp_sid = strtol (sid, NULL, 10); + if ((errno == EINVAL) || (errno == ERANGE)) + return MM_MODEM_CDMA_SID_UNKNOWN; + else if (tmp_sid < G_MININT || tmp_sid > G_MAXINT) + return MM_MODEM_CDMA_SID_UNKNOWN; + + return (gint) tmp_sid; } |