aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mm-charsets.c92
-rw-r--r--src/mm-charsets.h5
-rw-r--r--src/mm-generic-gsm.c43
3 files changed, 137 insertions, 3 deletions
diff --git a/src/mm-charsets.c b/src/mm-charsets.c
index f12ad30d..c2fa2298 100644
--- a/src/mm-charsets.c
+++ b/src/mm-charsets.c
@@ -87,6 +87,22 @@ charset_iconv_to (MMModemCharset charset)
return NULL;
}
+static const char *
+charset_iconv_from (MMModemCharset charset)
+{
+ CharsetEntry *iter = &charset_map[0];
+
+ g_return_val_if_fail (charset != MM_MODEM_CHARSET_UNKNOWN, NULL);
+
+ while (iter->gsm_name) {
+ if (iter->charset == charset)
+ return iter->iconv_from_name;
+ iter++;
+ }
+ g_warn_if_reached ();
+ return NULL;
+}
+
gboolean
mm_modem_charset_byte_array_append (GByteArray *array,
const char *string,
@@ -131,3 +147,79 @@ mm_modem_charset_byte_array_append (GByteArray *array,
return TRUE;
}
+/* From hostap, Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi> */
+
+static int hex2num (char c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return -1;
+}
+
+static int hex2byte (const char *hex)
+{
+ int a, b;
+ a = hex2num(*hex++);
+ if (a < 0)
+ return -1;
+ b = hex2num(*hex++);
+ if (b < 0)
+ return -1;
+ return (a << 4) | b;
+}
+
+static char *
+hexstr2bin (const char *hex, gsize *out_len)
+{
+ size_t len = strlen (hex);
+ size_t i;
+ int a;
+ const char * ipos = hex;
+ char * buf = NULL;
+ char * opos;
+
+ /* Length must be a multiple of 2 */
+ g_return_val_if_fail ((len % 2) == 0, NULL);
+
+ opos = buf = g_malloc0 ((len / 2) + 1);
+ for (i = 0; i < len; i += 2) {
+ a = hex2byte (ipos);
+ if (a < 0) {
+ g_free (buf);
+ return NULL;
+ }
+ *opos++ = a;
+ ipos += 2;
+ }
+ *out_len = len / 2;
+ return buf;
+}
+
+/* End from hostap */
+
+char *
+mm_modem_charset_hex_to_utf8 (const char *src, MMModemCharset charset)
+{
+ char *unconverted;
+ const char *iconv_from;
+ gsize unconverted_len = 0;
+
+ g_return_val_if_fail (src != NULL, NULL);
+ g_return_val_if_fail (charset != MM_MODEM_CHARSET_UNKNOWN, NULL);
+
+ iconv_from = charset_iconv_from (charset);
+ g_return_val_if_fail (iconv_from != NULL, FALSE);
+
+ unconverted = hexstr2bin (src, &unconverted_len);
+ g_return_val_if_fail (unconverted != NULL, NULL);
+
+ if (charset == MM_MODEM_CHARSET_UTF8 || charset == MM_MODEM_CHARSET_IRA)
+ return unconverted;
+
+ return g_convert (unconverted, unconverted_len, "UTF-8//TRANSLIT", iconv_from, NULL, NULL, NULL);
+}
+
diff --git a/src/mm-charsets.h b/src/mm-charsets.h
index 41d568dd..5fa34065 100644
--- a/src/mm-charsets.h
+++ b/src/mm-charsets.h
@@ -43,5 +43,10 @@ gboolean mm_modem_charset_byte_array_append (GByteArray *array,
gboolean quoted,
MMModemCharset charset);
+/* Take a string in hex representation ("00430052" or "A4BE11" for example)
+ * and convert it from the given character set to UTF-8.
+ */
+char *mm_modem_charset_hex_to_utf8 (const char *src, MMModemCharset charset);
+
#endif /* MM_CHARSETS_H */
diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c
index f13a7fff..f888d9d3 100644
--- a/src/mm-generic-gsm.c
+++ b/src/mm-generic-gsm.c
@@ -1408,8 +1408,37 @@ reg_info_updated (MMGenericGsm *self,
}
}
+static void
+convert_operator_from_ucs2 (char **operator)
+{
+ const char *p;
+ char *converted;
+ size_t len;
+
+ g_return_if_fail (operator != NULL);
+ g_return_if_fail (*operator != NULL);
+
+ p = *operator;
+ len = strlen (p);
+
+ /* Len needs to be a multiple of 4 for UCS2 */
+ if ((len < 4) && ((len % 4) != 0))
+ return;
+
+ while (*p) {
+ if (!isxdigit (*p++))
+ return;
+ }
+
+ converted = mm_modem_charset_hex_to_utf8 (*operator, MM_MODEM_CHARSET_UCS2);
+ if (converted) {
+ g_free (*operator);
+ *operator = converted;
+ }
+}
+
static char *
-parse_operator (const char *reply)
+parse_operator (const char *reply, MMModemCharset cur_charset)
{
char *operator = NULL;
@@ -1431,6 +1460,13 @@ parse_operator (const char *reply)
g_regex_unref (r);
}
+ /* 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 (operator && (cur_charset == MM_MODEM_CHARSET_UCS2))
+ convert_operator_from_ucs2 (&operator);
+
return operator;
}
@@ -1444,7 +1480,7 @@ read_operator_code_done (MMAtSerialPort *port,
char *oper;
if (!error) {
- oper = parse_operator (response->str);
+ oper = parse_operator (response->str, MM_MODEM_CHARSET_UNKNOWN);
if (oper)
reg_info_updated (self, FALSE, 0, TRUE, oper, FALSE, NULL);
}
@@ -1457,10 +1493,11 @@ read_operator_name_done (MMAtSerialPort *port,
gpointer user_data)
{
MMGenericGsm *self = MM_GENERIC_GSM (user_data);
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
char *oper;
if (!error) {
- oper = parse_operator (response->str);
+ oper = parse_operator (response->str, priv->cur_charset);
if (oper)
reg_info_updated (self, FALSE, 0, FALSE, NULL, TRUE, oper);
}